import React from 'react';
import { InMemoryCache } from '@apollo/client';
import { MockedProvider, MockedResponse } from '@apollo/client/testing';
import { waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { renderInAppContext } from '@theorchard/suite-testing';
import { getProductValidationData } from 'lib/mockProductData';
import { getMockReviewQueueItemData } from 'lib/test/mocks/mockreviewQueueItemData';
import {
    getMockEscalationGroupsQuery,
    mockProductPricingQuery,
    mockProductQuery,
} from 'lib/test/mocks/queries';
import {
    ProductValidationErrorCode,
    TrackValidationWarningCode,
} from 'src/constants';
import { typePolicies } from 'src/data';
import productValidationQuery from 'src/data/queries/productValidation/ProductValidationQuery.gql';
import * as reviewQueueItemQuery from 'src/data/queries/reviewQueueItem/reviewQueueItem';
import ProductModal from '../productModal';
import type {
    ProductValidationErrors,
    TrackValidationWarnings,
} from 'src/types';

const getMockProviderRequests = (
    productErrors: ProductValidationErrors = [],
    trackWarnings: TrackValidationWarnings = []
) => [
    getMockEscalationGroupsQuery(),
    mockProductQuery,
    mockProductQuery,
    mockProductPricingQuery,
    {
        request: {
            query: productValidationQuery,
            variables: {
                id: '33',
            },
        },
        result: {
            data: {
                product: getProductValidationData({
                    productErrors,
                    trackWarnings,
                }),
            },
        },
    },
];

describe('<ProductModal> Notices', () => {
    beforeEach(() =>
        jest
            .spyOn(reviewQueueItemQuery, 'useReviewQueueItemQuery')
            .mockImplementation(() => ({
                loading: false,
                error: undefined,
                data: getMockReviewQueueItemData(),
            }))
    );

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

    const render = (mockProviderRequests: readonly MockedResponse[]) =>
        renderInAppContext(
            <MockedProvider
                cache={
                    new InMemoryCache({
                        typePolicies,
                    })
                }
                mocks={mockProviderRequests}
            >
                <ProductModal
                    reviewQueueItems={[{ productId: 33 }, { productId: 222 }]}
                    currentReviewQueueItemId={33}
                    nextReviewQueueItemId={null}
                    productId={33}
                    queueName="initial"
                    submissionType="new"
                    reviewQueueItemQueryError={undefined}
                    isReviewQueueItemLocked
                    productTargetGroup={{ displayName: 'name', id: '1' }}
                    submittedByUserLanguage={null}
                    lockedByUserName={undefined}
                    wasExistingLockDetected
                />
            </MockedProvider>
        );

    describe('displays POTENTIAL_AUDIO_INFRINGEMENT warning', () => {
        test('displays new notice', async () => {
            window.HTMLElement.prototype.scrollIntoView = jest.fn();
            const mockProductRequests = getMockProviderRequests(
                [],
                [
                    {
                        code: TrackValidationWarningCode.POTENTIAL_AUDIO_INFRINGEMENT,
                        reason: '{"matches":[{"artists":["Focus Sounds"],"label":"Reseda Garage","title":"Pink Noise 1","songwhip_url":"https://songwhip.com/focussounds/pink-noise-1"},{"artists":["Vibrant Noise"],"label":"Vibrant Noise","title":"Pink Noise For Insomnia","songwhip_url":"https://songwhip.com/vibrantnoise/pink-noise-for-insomnia"}]}',
                    },
                ]
            );
            const { getByTestId, getByText } = render(mockProductRequests);

            const name = 'validationGroupPOTENTIAL_AUDIO_INFRINGEMENT';

            await waitFor(() => {
                expect(getByTestId(name)).toBeVisible();
            });

            userEvent.click(getByTestId(name));

            expect(
                window.HTMLElement.prototype.scrollIntoView
            ).toHaveBeenCalled();

            await waitFor(() => {
                const messageElement = getByText(
                    "This track's audio is publicly claimed, as shown below. If you approve it, please provide a reason for authorizing this track for distribution."
                );

                expect(messageElement).toBeVisible();
                // eslint-disable-next-line testing-library/no-wait-for-multiple-assertions
                expect(getByTestId('PotentialAudioInfringement')).toBeVisible();
                // eslint-disable-next-line testing-library/no-wait-for-multiple-assertions
                expect(getByText('See all matches (2)')).toBeVisible();
            });
        });
    });

    test.skip('displays PRODUCER_MISMATCH error', async () => {
        const mockProductRequests = getMockProviderRequests([
            {
                code: ProductValidationErrorCode.PRODUCER_MISMATCH,
                reason: 'some reason',
            },
        ]);
        const { getByTestId, getByText } = render(mockProductRequests);
        const name = 'validationGroupPRODUCER_MISMATCH';

        await waitFor(() => {
            expect(getByTestId(name)).toBeVisible();
        });

        userEvent.click(getByTestId(name));

        await waitFor(() => {
            const messageElement = getByText(
                'A producer on 100% of tracks must be listed as a producer on the product level.'
            );
            expect(messageElement).toBeVisible();
        });
    });

    test.skip('displays REMIXER_MISMATCH error', async () => {
        const mockProductRequests = getMockProviderRequests([
            {
                code: ProductValidationErrorCode.REMIXER_MISMATCH,
                reason: 'reason is not used by the frontend for this error code',
            },
        ]);
        const { getByTestId, getByText } = render(mockProductRequests);
        const name = 'validationGroupREMIXER_MISMATCH';
        await waitFor(() => {
            expect(getByTestId(name)).toBeVisible();
        });

        userEvent.click(getByTestId(name));

        await waitFor(() => {
            const messageElement = getByText(
                'A remixer on 100% of tracks must be listed as a remixer on the product level.'
            );
            expect(messageElement).toBeVisible();
        });
    });

    test('ignores CROSS_ACCOUNT_OSR_CONFLICT warning', async () => {
        const mockProductRequests = getMockProviderRequests(
            [],
            [
                {
                    code: TrackValidationWarningCode.CROSS_ACCOUNT_OSR_CONFLICT,
                    reason: 'reason is not used by the frontend for this error code',
                },
            ]
        );
        const { queryByTestId } = render(mockProductRequests);
        expect(
            queryByTestId('validationGroupCROSS_ACCOUNT_OSR_CONFLICT')
        ).not.toBeInTheDocument();
    });

    test('ignores track OSR validation warnings on a revised product', () => {
        const mockProductRequests = getMockProviderRequests(
            [],
            [
                {
                    code: TrackValidationWarningCode.CROSS_ISRC_OSR_MISMATCH,
                    reason: 'reason is not used by the frontend for this error code',
                },
                {
                    code: TrackValidationWarningCode.CROSS_TRACK_ISRC_MISMATCH,
                    reason: 'reason is not used by the frontend for this error code',
                },
            ]
        );
        const { queryByTestId } = render(mockProductRequests);
        expect(
            queryByTestId('validationGroupCROSS_ISRC_OSR_MISMATCH')
        ).not.toBeInTheDocument();
        expect(
            queryByTestId('validationGroupCROSS_TRACK_ISRC_MISMATCH')
        ).not.toBeInTheDocument();
    });

    test.skip('displays FEATURING_ARTIST_MISMATCH error', async () => {
        const mockProductRequests = getMockProviderRequests([
            {
                code: ProductValidationErrorCode.FEATURING_ARTIST_MISMATCH,
                reason: 'some reason',
            },
        ]);
        const { getByTestId, getByText } = render(mockProductRequests);
        const name = 'validationGroupFEATURING_ARTIST_MISMATCH';

        await waitFor(() => {
            expect(getByTestId(name)).toBeVisible();
        });

        userEvent.click(getByTestId(name));

        await waitFor(() => {
            const messageElement = getByText(
                'Featuring Artists on 100% of tracks must be listed as featuring artist on the product level.'
            );
            expect(messageElement).toBeVisible();
        });
    });

    test.skip('displays VARIOUS_ARTISTS_ON_FEATURING_ARTIST error', async () => {
        const mockProductRequests = getMockProviderRequests([
            {
                code: ProductValidationErrorCode.VARIOUS_ARTISTS_ON_FEATURING_ARTIST,
                reason: 'some reason',
            },
        ]);
        const { getByTestId, getByText } = render(mockProductRequests);
        const name = 'validationGroupVARIOUS_ARTISTS_ON_FEATURING_ARTIST';

        await waitFor(() => {
            expect(getByTestId(name)).toBeVisible();
        });

        userEvent.click(getByTestId(name));

        await waitFor(() => {
            const messageElement = getByText(
                'Please list all artists individually and do not use "Various Artists".'
            );
            expect(messageElement).toBeVisible();
        });
    });
});
