import React from 'react';
import { fireEvent } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { getMergedProduct, getProductMetadata } from 'lib/mockProductData';
import { Validation } from 'src/data/queries';
import {
    openSelect,
    selectOption,
} from '../../../../../../../tools/lib/test-utils/select';
import ProductModalApprovalSidecarV2 from '../productModalApprovalSidecarV2';
import { CLASS_NAME, Props } from '../productModalApprovalSidecarV2';
import {
    approveMutation,
    infringedMergedProduct,
    initializeRequestSpies,
    spotifyWatchlist,
} from './approval-test-helpers';

const defaultProps = {
    isOpen: true,
    product: getProductMetadata(),
    mergedProduct: getMergedProduct(),
    closeModal: jest.fn(),
    onReviewCompleted: jest.fn(),
    productReviewQueueId: 1,
};

describe('ProductModalApprovalSidecarV2', () => {
    const renderComponent = (props: Partial<Props> = {}) =>
        renderInAppContext(
            <ProductModalApprovalSidecarV2 {...defaultProps} {...props} />
        );

    beforeEach(() => {
        jest.clearAllMocks();

        initializeRequestSpies();
    });

    describe('Negative Approval flow states', () => {
        test('[Single Note Form] approve button is enabled if no warnings present', () => {
            const { getByTestId } = renderComponent();

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);

            expect(approveButton).toBeEnabled();
        });

        test('[Product Form] "Other" reason is selected without note', async () => {
            const { getByTestId } = renderComponent({
                validations: [spotifyWatchlist as Validation],
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const noteTextarea = getByTestId('product-approval-form-note');

            expect(approveButton).toBeDisabled();

            await openSelect('product-approval-form-reason');
            selectOption('Other');

            // Make sure there is no text in note textarea
            fireEvent.change(noteTextarea, {
                target: { value: '' },
            });

            expect(approveButton).toBeDisabled();
        });

        test('[Tracks Form] "Other" reason is selected without note', async () => {
            const { getByTestId } = renderComponent({
                mergedProduct: infringedMergedProduct,
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const noteTextarea = getByTestId('track-approval-form-note');

            expect(approveButton).toBeDisabled();

            await openSelect('track-approval-form-reason');
            selectOption('Other');

            // Make sure there is no text in note textarea
            fireEvent.change(noteTextarea, {
                target: { value: '' },
            });

            expect(approveButton).toBeDisabled();
        });

        test('[Tracks Form] "Other" reason is selected on individual track without note', async () => {
            const { getByTestId } = renderComponent({
                mergedProduct: infringedMergedProduct,
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const openTracks = getByTestId('open-tracks-header');
            const noteTextarea = getByTestId('track-approval-form-note');

            expect(approveButton).toBeDisabled();

            fireEvent.click(openTracks);

            await openSelect('track-approval-form-reason-123456');
            selectOption('Other');

            await openSelect('track-approval-form-reason-234567');
            selectOption('reason 2');

            // Make sure there is no text in note textarea
            fireEvent.change(noteTextarea, {
                target: { value: '' },
            });

            expect(approveButton).toBeDisabled();

            // Update note text to pass form validation
            fireEvent.change(noteTextarea, {
                target: { value: 'some value' },
            });

            expect(approveButton).toBeEnabled();
        });

        test('[Both Forms] Missing form data', async () => {
            const { getByTestId } = renderComponent({
                mergedProduct: infringedMergedProduct,
                validations: [spotifyWatchlist as Validation],
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const productNoteTextarea = getByTestId(
                'product-approval-form-note'
            );
            const trackNoteTextarea = getByTestId('track-approval-form-note');
            const openTracks = getByTestId('open-tracks-header');

            // Product and Tracks reasons are initially empty
            expect(approveButton).toBeDisabled();

            // Select Product reason as Other and leave Product Note empty
            await openSelect('product-approval-form-reason');
            selectOption('Other');

            fireEvent.change(productNoteTextarea, {
                target: { value: '' },
            });

            expect(approveButton).toBeDisabled();

            // Open individual tracks form
            fireEvent.click(openTracks);

            // Select first track reason as Other, second as reason 2 and leave Note empty
            await openSelect('track-approval-form-reason-123456');
            selectOption('Other');

            await openSelect('track-approval-form-reason-234567');
            selectOption('reason 2');

            fireEvent.change(trackNoteTextarea, {
                target: { value: '' },
            });

            expect(approveButton).toBeDisabled();

            // Add text to Product Note
            fireEvent.change(productNoteTextarea, {
                target: { value: 'some value' },
            });

            expect(approveButton).toBeDisabled();

            // Add text to Product Note
            fireEvent.change(trackNoteTextarea, {
                target: { value: 'some value' },
            });

            // Button is finally enabled
            expect(approveButton).toBeEnabled();
        });
    });

    describe('[Product Form] Positive Approval flow', () => {
        test('Successfully selecting reason and submitting form', async () => {
            const { getByTestId } = renderComponent({
                validations: [spotifyWatchlist as Validation],
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const noteTextarea = getByTestId('product-approval-form-note');

            await openSelect('product-approval-form-reason');
            selectOption('reason 1');

            fireEvent.change(noteTextarea, {
                target: { value: 'approval note' },
            });

            expect(approveButton).toBeEnabled();

            fireEvent.click(approveButton);

            expect(approveMutation).toHaveBeenCalledWith({
                cannedResponseIds: ['128'],
                note: '[Spotify Watchlist]\nReason: reason 1\napproval note',
                reviewQueueId: 1,
                tracks: [],
            });
        });
    });

    describe('[Tracks Form] Positive Approve flow', () => {
        test('Successfully selecting global reason and submitting form', async () => {
            const { getByTestId } = renderComponent({
                mergedProduct: infringedMergedProduct,
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const noteTextarea = getByTestId('track-approval-form-note');

            await openSelect('track-approval-form-reason');
            selectOption('reason 2');

            fireEvent.change(noteTextarea, {
                target: { value: 'track note' },
            });

            expect(approveButton).toBeEnabled();

            fireEvent.click(approveButton);

            expect(approveMutation).toHaveBeenCalledWith({
                cannedResponseIds: ['2'],
                note: '[Potential Audio Infringement]\nReason: reason 2\ntrack note',
                reviewQueueId: 1,
                tracks: [
                    {
                        trackId: 123456,
                        cannedResponseId: 2,
                    },
                    {
                        trackId: 234567,
                        cannedResponseId: 2,
                    },
                ],
            });
        });

        test('Successfully selecting track reasons individually and submitting form', async () => {
            const { getByTestId } = renderComponent({
                mergedProduct: infringedMergedProduct,
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const noteTextarea = getByTestId('track-approval-form-note');
            const openTracks = getByTestId('open-tracks-header');

            fireEvent.click(openTracks);

            await openSelect('track-approval-form-reason-123456');
            selectOption('reason 2');

            await openSelect('track-approval-form-reason-234567');
            selectOption('Other');

            fireEvent.change(noteTextarea, {
                target: { value: 'track note' },
            });

            expect(approveButton).toBeEnabled();

            fireEvent.click(approveButton);

            expect(approveMutation).toHaveBeenCalledWith({
                cannedResponseIds: [],
                note: '[Potential Audio Infringement]\nReason: Mixed\ntrack note',
                reviewQueueId: 1,
                tracks: [
                    {
                        trackId: 123456,
                        cannedResponseId: 2,
                    },
                    {
                        trackId: 234567,
                        cannedResponseId: 69,
                    },
                ],
            });
        });
    });

    describe('[Both Forms] Positive Approval flow', () => {
        test('Successfully selecting reasons on both forms and submitting', async () => {
            const { getByTestId } = renderComponent({
                mergedProduct: infringedMergedProduct,
                validations: [spotifyWatchlist as Validation],
            });

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const productNoteTextarea = getByTestId(
                'product-approval-form-note'
            );
            const trackNoteTextarea = getByTestId('track-approval-form-note');
            const openTracks = getByTestId('open-tracks-header');

            await openSelect('product-approval-form-reason');
            selectOption('reason 1');

            fireEvent.change(productNoteTextarea, {
                target: { value: 'product note' },
            });

            fireEvent.click(openTracks);

            await openSelect('track-approval-form-reason-123456');
            selectOption('reason 2');

            await openSelect('track-approval-form-reason-234567');
            selectOption('reason 2');

            fireEvent.change(trackNoteTextarea, {
                target: { value: 'track note' },
            });

            expect(approveButton).toBeEnabled();

            fireEvent.click(approveButton);

            expect(approveMutation).toHaveBeenCalledWith({
                cannedResponseIds: ['128', '2'],
                note: '[Spotify Watchlist]\nReason: reason 1\nproduct note\n\n[Potential Audio Infringement]\nReason: reason 2\ntrack note',
                reviewQueueId: 1,
                tracks: [
                    {
                        trackId: 123456,
                        cannedResponseId: 2,
                    },
                    {
                        trackId: 234567,
                        cannedResponseId: 2,
                    },
                ],
            });
        });
    });

    describe('[Single Note Form] Positive Approval flow with no warnings', () => {
        test('Submitting form with only single note', async () => {
            const { getByTestId } = renderComponent();

            const approveButton = getByTestId(`${CLASS_NAME}-confirm-button`);
            const noteTextarea = getByTestId(
                'form-control-additional-notes-approval'
            );

            fireEvent.change(noteTextarea, {
                target: { value: 'single note' },
            });

            expect(approveButton).toBeEnabled();

            fireEvent.click(approveButton);

            expect(approveMutation).toHaveBeenCalledWith({
                cannedResponseIds: [],
                note: 'single note',
                reviewQueueId: 1,
                tracks: [],
            });
        });
    });
});
