import React from 'react';
import { act, fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { waitForLoaded } from 'lib/test/helpers';
import * as deletePublisher from 'src/data/mutations/deletePublisher/deletePublisher';
import * as orchardLabels from 'src/data/queries/orchardLabels/orchardLabels';
import * as publishers from 'src/data/queries/publishers/publishers';
import PublishersListPage from 'src/pages/publishersListPage';
import * as applicationContext from 'src/utils/applicationContext';
import {
    generateNMockPublishers,
    orchardLabelsMock,
    publishersMock,
} from '../mocks';

describe('<PublishersListPage>', () => {
    const deletePublisherSpy = jest.fn();

    const renderComponent = (page = 1, contextProps = {}) => {
        const defaultProps = { pathname: `/publishers/${page}` };

        const props = {
            ...defaultProps,
            ...contextProps,
        };

        return renderInAppContext(<PublishersListPage />, props);
    };

    beforeEach(() => {
        jest.spyOn(publishers, 'usePublishingPublishers').mockReturnValue({
            error: undefined,
            loading: false,
            data: publishersMock,
            refetch: jest.fn(),
            networkStatus: 7,
        });

        jest.spyOn(
            deletePublisher,
            'useDeletePublisherMutation'
        ).mockReturnValue(deletePublisherSpy);
        jest.spyOn(orchardLabels, 'useOrchardLabels').mockReturnValue({
            loading: false,
            error: undefined,
            data: orchardLabelsMock,
        });
    });

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

    test('can view through the options glyph', async () => {
        const { container } = renderComponent();
        await waitForLoaded();

        const glyphIcon = container?.querySelector(
            '.OptionsHorizontalGlyphIcon'
        )?.parentElement;
        if (!glyphIcon)
            throw new Error('Could not find .OptionsHorizontalGlyphIcon');
        fireEvent.click(glyphIcon);

        const viewBtn = screen.getByText('View');
        fireEvent.click(viewBtn);

        expect(await screen.findByText('Publisher Info')).toBeTruthy();
        expect(
            await screen.findByText(
                `${publishersMock.publishers[0].vendor.name} - ${publishersMock.publishers[0].vendor.id.vendorId}`
            )
        ).toBeTruthy();
        expect(
            (await screen.findAllByText(publishersMock.publishers[0].name))
                .length
        ).toEqual(2);
        expect(
            (await screen.findAllByText(publishersMock.publishers[0].pro))
                .length
        ).toEqual(2);
        expect(
            (await screen.findAllByText(publishersMock.publishers[0].ipi))
                .length
        ).toEqual(2);
        expect(
            await screen.findByText(
                publishersMock.publishers[0].agreements[0].songWriter.legalName
            )
        ).toBeTruthy();
        expect(
            await screen.findByText(
                publishersMock.publishers[0].agreements[0].songWriter.pro
            )
        ).toBeTruthy();
        expect(
            await screen.findByText(
                publishersMock.publishers[0].agreements[0].songWriter.ipi
            )
        ).toBeTruthy();
        expect(
            await screen.findByText(
                publishersMock.publishers[0].agreements[1].songWriter.legalName
            )
        ).toBeTruthy();
        expect(
            await screen.findByText(
                publishersMock.publishers[0].agreements[1].songWriter.pro
            )
        ).toBeTruthy();
        expect(
            await screen.findByText(
                publishersMock.publishers[0].agreements[1].songWriter.ipi
            )
        ).toBeTruthy();
    });

    test('can show empty state', async () => {
        jest.spyOn(publishers, 'usePublishingPublishers').mockReturnValue({
            error: undefined,
            loading: false,
            networkStatus: 7,
            data: {
                totalCount: 0,
                publishers: [],
            },
            refetch: jest.fn(),
        });

        renderComponent();
        await waitForLoaded();

        expect(screen.getByText('You Have No Publishers')).toBeTruthy();
    });

    test('common Label Picker should be render at header', async () => {
        const { container } = renderComponent();

        await waitForLoaded();

        const headerLabelPicker = container.querySelector(
            '.PublishersListPage .AppHeader .HeaderLabelPicker .LabelSearchDropdown'
        );
        expect(headerLabelPicker).toBeTruthy();

        const pageTitle = container.querySelector(
            '.PublishersListPage .AppHeader .breadcrumb'
        );
        expect(pageTitle).toBeFalsy();

        const listingLabelPickers = container.querySelector(
            '.PublishersListPage .PageControls .LabelSearchDropdown'
        );
        expect(listingLabelPickers).toBeFalsy();
    });

    test('can not delete an existing publisher if publisher has associated songwriter', async () => {
        const { container, getByText, queryByText } = renderComponent();
        await waitForLoaded();

        const glyphIcon = container.querySelector(
            '.OptionsHorizontalGlyphIcon'
        )?.parentElement;
        if (!glyphIcon)
            throw new Error('Could not find .OptionsHorizontalGlyphIcon');
        fireEvent.click(glyphIcon);

        const deleteButton = getByText('Delete');
        fireEvent.click(deleteButton);

        await waitFor(() =>
            expect(
                queryByText('Yes, I want to delete this publisher')
            ).toBeFalsy()
        );
    });

    test('can delete an existing publisher if publisher does not have associated song writer', async () => {
        jest.spyOn(publishers, 'usePublishingPublishers').mockReturnValue({
            error: undefined,
            loading: false,
            networkStatus: 7,
            data: {
                totalCount: 0,
                publishers: [publishersMock.publishers[1]],
            },
            refetch: jest.fn(),
        });

        const { container, getByText } = renderComponent();
        await waitForLoaded();

        const glyphIcon = container.querySelector(
            '.OptionsHorizontalGlyphIcon'
        )?.parentElement;
        if (!glyphIcon)
            throw new Error('Could not find .OptionsHorizontalGlyphIcon');
        fireEvent.click(glyphIcon);

        const deleteButton = getByText('Delete');
        fireEvent.click(deleteButton);

        const confirmDeleteButton = getByText(
            'Yes, I want to delete this publisher'
        );
        expect(confirmDeleteButton).toBeTruthy();

        fireEvent.click(confirmDeleteButton);
        expect(deletePublisherSpy).toHaveBeenCalledWith({
            variables: { id: publishersMock.publishers[1].id },
        });
    });

    test('can change pagesize', async () => {
        const mockData = generateNMockPublishers();
        const publishersQueryMock = jest
            .spyOn(publishers, 'usePublishingPublishers')
            .mockReturnValue({
                error: undefined,
                loading: false,
                data: mockData,
                refetch: jest.fn(),
                networkStatus: 7,
            });

        let selectedPageSize = 0;
        renderComponent();
        await act(async () => {
            await waitForLoaded();
        });

        const paginationMessage = (
            await screen.findAllByTestId('SuitePagination-message')
        )[0];
        await waitFor(() => {
            expect(paginationMessage).toBeTruthy();
        });
        act(() => {
            paginationMessage.click();
        });

        selectedPageSize = parseInt(
            (await screen.findAllByTestId('SegmentedButton-btn-text'))[0]
                .textContent || '0',
            10
        );

        (await screen.findAllByTestId('SegmentedButton-btn-text'))[0].click();

        await waitFor(() => {
            expect(publishersQueryMock).toHaveBeenLastCalledWith(
                {
                    label: null,
                    nameOrIpiSearch: null,
                },
                1,
                selectedPageSize
            );
        });
    });

    test('uses params from ApplicationContext', async () => {
        jest.spyOn(applicationContext, 'useApplicationContext').mockReturnValue(
            {
                label: null,
                setLabel: jest.fn(),
                labelAlt: null,
                setLabelAlt: jest.fn(),
                pageFilters: {
                    publishersPagePublisherSearch: '540 Music',
                },
                updatePageFilters: jest.fn(),
            }
        );
        const publishersQueryMock = jest.spyOn(
            publishers,
            'usePublishingPublishers'
        );

        renderComponent();
        await act(async () => {
            await waitForLoaded();
        });

        await waitFor(() => {
            expect(publishersQueryMock).toHaveBeenLastCalledWith(
                {
                    label: null,
                    nameOrIpiSearch: '540 Music',
                },
                1,
                25
            );
        });
    });
});
