import React from 'react';
import * as apollo from '@apollo/client';
import { fireEvent, screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { getMergedProduct, getMockProductTrack } from 'lib/mockProductData';
import * as upsertTracksAudioAttributesEdits from 'src/data/mutations/upsertTracksAudioAttributesEdits/upsertTracksAudioAttributesEdits';
import * as upsertTracksRightsAttributesEdits from 'src/data/mutations/upsertTracksRightsAttributesEdits/upsertTracksRightsAttributesEdits';
import * as audioAttributesQueries from 'src/data/queries/audioAttributes/audioAttributes';
import { Product } from 'src/data/queries/product/types';
import * as rightsAttributesQueries from 'src/data/queries/rightsAttributes/rightsAttributes';
import {
    getAudioAttributesInput,
    replicateTrackAudioAttributesFromEdits,
} from 'src/utils/attributes';
import ProductTrackAttributesPopoverContent, {
    CLASS_NAME,
    Props,
} from '../productTrackAttributesPopoverContent';

const upsertAudioAttributesEditsMock = jest.fn();
const upsertRightsAttributesEditsMock = jest.fn();

describe('ProductTrackAttributesPopoverContent', () => {
    beforeEach(() => {
        jest.spyOn(
            audioAttributesQueries,
            'useAudioAttributesQuery'
        ).mockReturnValue({
            loading: false,
            data: [
                {
                    description: 'N/A',
                    id: '1',
                },
                {
                    description: 'Classical - Contemporary',
                    id: '3',
                },
                {
                    description: 'Classical - Traditional',
                    id: '4',
                },
                {
                    description: 'Comedy',
                    id: '8',
                },
            ],
            error: false,
        });

        jest.spyOn(
            rightsAttributesQueries,
            'useRightsAttributesQuery'
        ).mockReturnValue({
            loading: false,
            data: [
                {
                    description: 'N/A',
                    id: '10',
                },
                {
                    description: 'Compilations',
                    id: '2',
                },
                {
                    description: 'Potential non-exclusive',
                    id: '5',
                },
            ],
            error: false,
        });

        jest.spyOn(
            upsertTracksAudioAttributesEdits,
            'useUpsertTracksAudioAttributesEditsMutation'
        ).mockReturnValue([
            upsertAudioAttributesEditsMock.mockReturnValue({
                catch: jest.fn(),
            }),
            {} as apollo.MutationResult,
        ]);

        jest.spyOn(
            upsertTracksRightsAttributesEdits,
            'useUpsertTracksRightsAttributesEditsMutation'
        ).mockReturnValue([
            upsertRightsAttributesEditsMock.mockReturnValue({
                catch: jest.fn(),
            }),
            {} as apollo.MutationResult,
        ]);
    });

    const renderComponent = (partialProps: Partial<Product> = {}) => {
        const mockProduct = getMergedProduct({
            productId: 1,
            tracks: [
                getMockProductTrack(),
                getMockProductTrack({
                    isrc: 'abc',
                    tuid: '456789',
                    trackNumber: 2,
                }),
            ],
            ...partialProps,
        });
        const defaultProps: Props = {
            tracks: mockProduct.getTrackList(),
            selectedRow: mockProduct.getTrackList()[0],
            close: jest.fn(),
        };
        const props: Props = { ...defaultProps };

        return renderInAppContext(
            <ProductTrackAttributesPopoverContent {...props} />
        );
    };

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

    describe('renders with no errors', () => {
        test('multi select', () => {
            const { getByTestId } = renderComponent();

            const wrapperEl = getByTestId(CLASS_NAME);
            expect(wrapperEl).toBeInTheDocument();

            const labelAudioEl =
                wrapperEl.getElementsByClassName('form-label')[0];
            const labelRightsEl =
                wrapperEl.getElementsByClassName('form-label')[1];
            const labelRightsText = $t(
                'contentReview.productTrackAttributesPopoverContent.multiSelectRightsTitle'
            );
            const labelAudioText = $t(
                'contentReview.productTrackAttributesPopoverContent.multiSelectAudioTitle'
            );
            expect(labelAudioEl).toHaveTextContent(labelAudioText);
            expect(labelRightsEl).toHaveTextContent(labelRightsText);

            const multiSelectAudioEl = wrapperEl.getElementsByClassName(
                'ProductTrackAttributesPopoverContent-multiselect-audio'
            )[0];
            expect(multiSelectAudioEl).toBeInTheDocument();
            const multiSelectRightsEl = wrapperEl.getElementsByClassName(
                'ProductTrackAttributesPopoverContent-multiselect-rights'
            )[0];
            expect(multiSelectRightsEl).toBeInTheDocument();
        });

        test('append to all checkbox', () => {
            const { getByTestId } = renderComponent();

            const wrapperEl = getByTestId(CLASS_NAME);
            expect(wrapperEl).toBeInTheDocument();

            const checkboxAudioEl =
                wrapperEl.getElementsByClassName('FormCheckbox')[0];
            const checkboxRightsEl =
                wrapperEl.getElementsByClassName('FormCheckbox')[1];

            expect(checkboxAudioEl).toBeInTheDocument();
            expect(checkboxRightsEl).toBeInTheDocument();
        });

        test('on confirm', async () => {
            const { getByTestId } = renderComponent();

            const wrapperEl = getByTestId(CLASS_NAME);

            const multiSelectAudioEl = wrapperEl.querySelector(
                '.ProductTrackAttributesPopoverContent-multiselect-audio .SuiteSelect-input'
            );
            if (multiSelectAudioEl) fireEvent.click(multiSelectAudioEl);

            const comedyOption = screen.getByText('Comedy', {
                selector: '.SuiteListView .SuiteListView-option-label',
            });
            fireEvent.click(comedyOption);

            const btn = getByTestId(`${CLASS_NAME}-done`);
            fireEvent.click(btn);

            expect(upsertAudioAttributesEditsMock).toHaveBeenCalledWith({
                variables: {
                    input: [{ audioAttributeIds: ['1', '8'], tuid: '123456' }],
                },
            });
            expect(upsertRightsAttributesEditsMock).toHaveBeenCalledWith({
                variables: {
                    input: [{ rightsAttributeIds: ['1'], tuid: '123456' }],
                },
            });
        });
    });

    describe('apply-to-all', () => {
        test('does not mark unchanged tracks as revised, preserving their suggestion on Approve', () => {
            const tracks = getMergedProduct({
                productId: 1,
                tracks: [
                    getMockProductTrack({
                        tuid: '123456',
                        audioAttributes: [],
                        audioAttributesEdits: [],
                        suggestedAudioAttributes: [
                            {
                                attribute: {
                                    id: '3',
                                    description: 'Classical - Contemporary',
                                },
                            },
                        ],
                    }),
                    getMockProductTrack({
                        tuid: '456789',
                        audioAttributes: [],
                        audioAttributesEdits: [],
                        suggestedAudioAttributes: [
                            {
                                attribute: {
                                    id: '4',
                                    description: 'Classical - Traditional',
                                },
                            },
                        ],
                    }),
                ],
            }).getTrackList();

            const { getByTestId } = renderInAppContext(
                <ProductTrackAttributesPopoverContent
                    tracks={tracks}
                    selectedRow={tracks[0]}
                    close={jest.fn()}
                />
            );

            // Enable "apply audio to all tracks" without changing the selection.
            const appendAudioCheckbox = getByTestId(
                CLASS_NAME
            ).querySelectorAll(
                '.ProductTrackAttributesPopoverContent-append-to-all-checkbox input'
            )[0];
            fireEvent.click(appendAudioCheckbox);

            fireEvent.click(getByTestId(`${CLASS_NAME}-done`));

            // No track's audio selection actually changed, so none should be
            // flagged as revised.
            expect(tracks[0].audioAttributesEdits.isRevised).toBe(false);
            expect(tracks[1].audioAttributesEdits.isRevised).toBe(false);

            // On Approve each track therefore keeps its suggestion rather than
            // being overwritten with N/A.
            replicateTrackAudioAttributesFromEdits(tracks);
            expect(getAudioAttributesInput(tracks, [])).toEqual([
                { tuid: '123456', audioAttributeIds: ['3'] },
                { tuid: '456789', audioAttributeIds: ['4'] },
            ]);
        });
    });
});
