import React from 'react';
import * as apollo from '@apollo/client';
import { fireEvent, screen } from '@testing-library/react';
import { Identity } from '@theorchard/suite-frontend';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import * as nrUpload from 'src/data/queries/nrUploadToken/nrUploadToken';
import { CreatePageProps } from 'src/pages/createPage/types';
import * as awsUtils from 'src/utils/aws';
import * as featureFlags from 'src/utils/features';
import * as validator from '../../uploadBox/validator';
import CsvUpload from '../csvUpload';

jest.mock('../../uploadBox/validator');

describe('<CsvUpload>', () => {
    const uploadTokenData = {
        credentials: {
            sessionToken: 'session-token',
            expiration: 'expiration-date',
            accessKeyId: 'AWSKEY',
            secretAccessKey: 'dw/secret',
        },
        filename: 'abcdef123456-214892148929481',
        bucket: 'neighbouring-rights',
    };
    beforeEach(() => {
        jest.spyOn(nrUpload, 'useLazyUploadToken').mockReturnValue([
            jest.fn(),
            {
                data: { nrUploadToken: uploadTokenData },
            } as apollo.QueryResult,
        ]);
        jest.spyOn(featureFlags, 'useUpload').mockReturnValue(true);
    });

    afterEach(() => {
        jest.restoreAllMocks();
    });

    const defaultProps: CreatePageProps = {
        report: null,
        toggleRecordIdLookup: jest.fn(),
        closeSidecar: false,
        s3UploadComplete: null,
        handleFileErrors: jest.fn(),
        handleS3Uploaded: jest.fn(),
        reportGenerationError: false,
        handleReportGenerationComplete: jest.fn(),
        handleReportGenerationError: jest.fn(),
    };

    const renderWrapper = (
        props?: Partial<CreatePageProps>,
        identity?: Identity
    ) =>
        renderInAppContext(<CsvUpload {...defaultProps} {...props} />, {
            identity,
        });

    const bothRoles = createIdentity({
        roles: ['manage_nr_repertoire', 'manage_nr_ownership'],
    });

    describe('On creating performance sound recordings', () => {
        describe('On valid file drop', () => {
            beforeEach(() => {
                jest.spyOn(validator, 'validateCsvData').mockReturnValue(
                    Promise.resolve(null)
                );
                jest.spyOn(awsUtils, 'uploadFileToS3').mockImplementation(
                    async () =>
                        await new Promise(resolve => {
                            setTimeout(() => resolve({ $metadata: {} }), 100);
                        })
                );
            });

            afterEach(() => jest.restoreAllMocks());

            test('renders loading spinner as file uploads', async () => {
                renderWrapper({}, bothRoles);

                const inputEl = screen.getByTestId('UploadBox');
                const file = new File(['file'], 'test.csv', {
                    type: 'text/csv',
                });
                Object.defineProperty(inputEl, 'files', { value: [file] });
                fireEvent.drop(inputEl);

                expect(
                    await screen.findByTestId('LoadingSpinner')
                ).toBeInTheDocument();
            });
        });

        describe('On invalid file', () => {
            const fileErrors = [{ code: 'error', message: 'some file error' }];
            beforeEach(() =>
                jest
                    .spyOn(validator, 'validateCsvData')
                    .mockReturnValue(Promise.resolve(fileErrors))
            );

            afterEach(() => jest.restoreAllMocks());

            test('shows error message', async () => {
                const file = new File(['file'], 'test.jpg', {
                    type: 'image/jpeg',
                });
                const props = {
                    ...defaultProps,
                    fileErrors: { errors: fileErrors, file },
                };
                renderWrapper(props, bothRoles);

                expect(
                    await screen.findByText(
                        $t('neighbouringRights.uploadErrors.uploadFailed')
                    )
                ).toBeInTheDocument();
                expect(
                    await screen.findByText(
                        $t('neighbouringRights.uploadErrors.reUpload')
                    )
                ).toBeInTheDocument();
            });
        });
    });
});
