import React from 'react';
import { screen, waitFor } from '@testing-library/react';
import { Identity } from '@theorchard/suite-frontend';
import { renderInAppContext } from '@theorchard/suite-testing';
import { contractDetails as mockContract } from 'src/__fixtures__/graphql/contract-details';
import * as contractTermQuery from 'src/apollo/queries/contract-term';
import * as productQuery from 'src/apollo/queries/product-search';
import * as trackQuery from 'src/apollo/queries/track-search';
import * as vendorQuery from 'src/apollo/queries/vendor-search';
import ContractTermDetail, {
    type ContractTermDetailProps,
} from 'src/components/contract-detail/contract-term-detail';
import { CONTRACT_TERM_TYPES, USER_FEATURES } from 'src/constants';
import { ContractTermContext } from 'src/contexts/contract-term-context';
import { initialTermsState } from 'src/reducers/contract-term/contract-terms-details-reducer';

const componentInContext = (
    contextValues: any,
    props: ContractTermDetailProps
) => (
    <ContractTermContext.Provider value={contextValues}>
        <ContractTermDetail {...props} />
    </ContractTermContext.Provider>
);

describe('<ContractTermDetail>', () => {
    const { contractTerms } = mockContract.abacusContract;
    const mockLabel = {
        orchardLabel: { id: { vendorId: 32486 }, name: 'Some Name' },
    };
    const mockProduct = {
        productByUpc: { productName: 'Product Exception Name' },
    };
    const mockTrack = [
        { data: { globalSoundRecordingByIsrc: { name: 'FirstTrackName' } } },
        { data: { globalSoundRecordingByIsrc: { name: 'SomeTrackName' } } },
        { data: { globalSoundRecordingByIsrc: { name: 'AwesomeTrackName' } } },
    ];
    const mockContractAttachmentsObjects = {
        abacusContractTerm: { contractTermId: 1, attachmentsObjects: [] },
    };
    const mockIdentity: Identity = {
        features: {
            [USER_FEATURES.ABACUS_SHOW_NR_CONTRIBUTIONS]: true,
        },
        id: '',
    };
    const render = (
        contextValues: any,
        props: ContractTermDetailProps,
        identity: Identity = {} as Identity
    ) =>
        renderInAppContext(componentInContext(contextValues, props), {
            identity,
        });
    const contextValues = { state: initialTermsState, dispatch: jest.fn() };
    const props: ContractTermDetailProps = {
        contractTerms: contractTerms as any, // fixture type doesn't exactly match
    };

    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        jest.spyOn(vendorQuery, 'useVendorById').mockReturnValue({
            data: mockLabel,
            getVendorById: jest.fn().mockReturnValue(mockLabel),
            loading: false,
        });

        jest.spyOn(productQuery, 'useProductByUpc').mockReturnValue({
            // @ts-expect-error fixture types don't exactly match
            data: mockProduct,
            getProductByUpc: jest.fn().mockReturnValue(mockProduct),
            loading: false,
        });

        jest.spyOn(trackQuery, 'useTrackByBatchIsrc').mockReturnValue({
            data: mockTrack,
            error: false,
            loading: false,
        });
        jest.spyOn(
            contractTermQuery,
            'useContractAttachmentsObjects'
        ).mockReturnValue({
            // @ts-expect-error fixture types don't exactly match
            data: mockContractAttachmentsObjects,
            error: undefined,
            networkStatus: null,
            fetchMore: (() => {}) as any,
        });
    });

    it('renders ContractTermDetail', () => {
        const { container } = render(contextValues, props);
        expect(container).toBeDefined();
        expect(screen.getByText('Transaction type')).toBeDefined();
        expect(screen.getByText('label')).toBeDefined();
        expect(
            screen.getByTestId('ContractTermConditionsTable-header')
        ).toHaveTextContent('Term Id');
    });

    it('renders ProductExceptions', () => {
        const { container } = render(contextValues, props);
        expect(
            container.querySelector('.ContractTermProductName')
        ).toBeDefined();
    });

    it('renders TrackExceptions', async () => {
        const { container } = render(contextValues, props);
        expect(
            container.querySelector('.TrackExceptions-trackName')
        ).toBeDefined();
        const element = screen.getByTestId('tracksNamesTestId');
        await waitFor(() => {
            expect(element.textContent).toEqual(
                'AwesomeTrackName -FirstTrackName -SomeTrackName -'
            );
        });
    });

    describe('renders correctly base terms', () => {
        it("doesn't render base terms block if contract terms are not base term", () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: false,
                    },
                ] as any, // fixture type doesn't exactly match
            };
            const { container } = render(contextValues, customProps);
            expect(container.querySelector('.BaseTerm-attachment')).toBeNull();
        });

        it('renders product type terms with the correct label', () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: true,
                        baseTerms: [contractTerms[0]],
                        termType: CONTRACT_TERM_TYPES.PRODUCT,
                    },
                ] as any, // fixture type doesn't exactly match
            };
            render(contextValues, customProps);
            expect(screen.getByTestId('typeLabelTestId')).toHaveTextContent(
                'Product'
            );
        });

        it('renders track type terms with the correct label', () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: true,
                        baseTerms: [contractTerms[0]],
                        termType: CONTRACT_TERM_TYPES.TRACK,
                    },
                ] as any, // fixture type doesn't exactly match
            };
            render(contextValues, customProps);
            expect(screen.getByTestId('typeLabelTestId')).toHaveTextContent(
                'Track'
            );
        });

        it('renders label type terms with the correct label', () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: true,
                        baseTerms: [contractTerms[0]],
                        termType: CONTRACT_TERM_TYPES.LABEL,
                    },
                ] as any, // fixture type doesn't exactly match
            };
            render(contextValues, customProps);
            expect(
                screen
                    .getByTestId('typeLabelTestId')
                    .querySelector('.form-label')
            ).toHaveTextContent('label');
        });

        it('renders contribution type terms with the correct label', () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: true,
                        baseTerms: [contractTerms[0]],
                        termType: CONTRACT_TERM_TYPES.CONTRIBUTION,
                        attachments: [],
                        attachmentsRelations: {
                            contributors: [
                                {
                                    name: 'Dickinson, Paul Bruce',
                                    id: '9514af96-8797-441f-ba55-a5b4452e7a5a',
                                },
                            ],
                        },
                    },
                ] as any, // fixture type doesn't exactly match
            };
            render(contextValues, customProps, mockIdentity);
            expect(screen.getByTestId('typeLabelTestId')).toHaveTextContent(
                'Contribution'
            );
        });

        it('does not render contribution type terms with correct label when ff off', () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: true,
                        baseTerms: [contractTerms[0]],
                        termType: CONTRACT_TERM_TYPES.CONTRIBUTION,
                        attachments: [],
                        attachmentsRelations: {
                            contributors: [
                                {
                                    name: 'Dickinson, Paul Bruce',
                                    id: '9514af96-8797-441f-ba55-a5b4452e7a5a',
                                },
                            ],
                        },
                    },
                ] as any, // fixture type doesn't exactly match
            };
            render(contextValues, customProps);
            expect(screen.getByTestId('typeLabelTestId')).toHaveTextContent('');
        });

        it('renders contribution type table values correctly', () => {
            const customProps = {
                contractTerms: [
                    {
                        ...contractTerms[0],
                        isBaseTerm: true,
                        baseTerms: [contractTerms[0]],
                        termType: CONTRACT_TERM_TYPES.CONTRIBUTION,
                        attachments: [],
                        attachmentsRelations: {
                            contributors: [
                                {
                                    name: 'Dickinson, Paul Bruce',
                                    id: '1',
                                },
                            ],
                        },
                    },
                ] as any, // fixture type doesn't exactly match
            };
            render(contextValues, customProps, mockIdentity);

            // contributors renders in table
            expect(
                screen.getByTestId('ContractTermConditionsTable-header')
            ).toHaveTextContent('Contributors');
            expect(screen.getByTestId('contributorsTestId')).toHaveTextContent(
                'Dickinson, Paul Bruce (1)'
            );

            // removes the edit button
            expect(screen.queryByTestId('TermEditButton')).toBeFalsy();
        });
    });
});
