import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { screen, fireEvent, waitFor } from '@testing-library/react';
import ContractTermDetailPresentationalHeader, {
    ContractTermDetailPresentationalHeaderPropTypes,
    sortSidecarItems,
} from '../contract-term-detail-presentational-header';
import { ABACUS_PROFILE, CONTRACT_TERM_TYPES } from 'src/constants';
import { ContractTermFormattedPresentational } from 'src/types/contract-term';
import { updateTerms } from 'src/urls/frontend-royalties';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';

jest.mock('@theorchard/suite-icons', () => ({
    GlyphIcon: (props: any) => <span {...props} />,
    SideCar: (props: any) => <div {...props} />,
}));

jest.mock('../../../apollo/queries/track-search', () => ({
    useTrackByBatchIsrc: () => [
        {
            data: {
                globalSoundRecordingByIsrc: {
                    isrc: 'isrc1',
                    name: 'isrc_1_name',
                },
            },
        },
        {
            data: {
                globalSoundRecordingByIsrc: {
                    isrc: 'isrc2',
                    name: 'isrc_2_name',
                },
            },
        },
    ],
}));

jest.mock('../../../apollo/queries/vendor-search', () => ({
    useVendorById: () => ({
        getVendorById: async () => ({
            orchardLabel: {
                id: {
                    vendorId: '1234',
                },
                name: 'labelName1234',
            },
        }),
    }),
}));

const setup = (
    overrideProps: Partial<ContractTermDetailPresentationalHeaderPropTypes> = {}
) => {
    const identity = createIdentity({ profileType: ABACUS_PROFILE });

    const defaultProps: ContractTermDetailPresentationalHeaderPropTypes = {
        contractTermLabelIndex: 0,
        contractTermFormattedDataMapIndex: 1,
        termType: CONTRACT_TERM_TYPES.TRACK,
        labelId: '1234',
        contractTermFormattedDataObject: {
            termId: 'TERM-1',
            catalogLength: 10,
            labelIds: ['1234'],
            contractTermName: 'Label Term 1',
            details: [],
            attachments: ['isrc1', 'isrc2'],
            termType: CONTRACT_TERM_TYPES.TRACK,
        } as ContractTermFormattedPresentational,
        contractId: '999',
        allAttachments: [
            { name: 'isrc1', value: 'isrc1' },
            { name: 'isrc2', value: 'isrc2' },
        ],
    };

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

    return renderInAppContext(
        <MemoryRouter>
            <ContractTermDetailPresentationalHeader {...props} />
        </MemoryRouter>,
        {
            identity,
        }
    );
};

describe('SortSideCarItems', () => {
    it('sorts the list first by label(name) and then by subtitle(isrc)', () => {
        const unsortedSideCarItemsIsrc = [
            {
                label: 'name2',
                subtitle: 'isrc3',
            },
            {
                label: 'name1',
                subtitle: 'isrc2',
            },
            {
                label: 'name1',
                subtitle: 'isrc1',
            },
        ];

        const sortedSideCarItemsIsrc = [
            {
                label: 'name1',
                subtitle: 'isrc1',
            },
            {
                label: 'name1',
                subtitle: 'isrc2',
            },
            {
                label: 'name2',
                subtitle: 'isrc3',
            },
        ];
        const sortedItems = sortSidecarItems(unsortedSideCarItemsIsrc);
        expect(sortedItems).toEqual(sortedSideCarItemsIsrc);
    });

    it('sorts the list first by label(name) and then by subtitle(upc)', () => {
        const unsortedSideCarItemsUpc = [
            {
                label: 'name2',
                subtitle: '123456',
            },
            {
                label: 'name1',
                subtitle: '234567',
            },
            {
                label: 'name1',
                subtitle: '12345671',
            },
        ];

        const sortedSideCarItemsUpc = [
            {
                label: 'name1',
                subtitle: '12345671',
            },
            {
                label: 'name1',
                subtitle: '234567',
            },
            {
                label: 'name2',
                subtitle: '123456',
            },
        ];
        const sortedItems = sortSidecarItems(unsortedSideCarItemsUpc);
        expect(sortedItems).toEqual(sortedSideCarItemsUpc);
    });
});

describe('ContractTermDetailPresentationalHeader', () => {
    it('renders without crashing', () => {
        const { container } = setup();
        expect(container).toBeInTheDocument();
    });

    it('displays accountName (and ID) if termType is label', async () => {
        setup({
            termType: CONTRACT_TERM_TYPES.LABEL,
            labelId: '1234',
            contractTermFormattedDataObject: {
                termId: 'TERM-ABC',
                contractTermName: null,
            } as ContractTermFormattedPresentational,
        });
        expect(
            screen.getByTestId('ContractTermLabelNamePresentational-testId')
        ).toBeInTheDocument();
        expect(screen.getByText(/TERM-ABC/)).toBeInTheDocument(); // The `termId`
        expect(
            screen.getByTestId('ContractPresentationalTermName').innerHTML
        ).toEqual('');
    });

    it('displays catalogLength + "termType + s" if termType != label', () => {
        setup({
            termType: CONTRACT_TERM_TYPES.PRODUCT,
            contractTermFormattedDataObject: {
                termId: '2345',
                catalogLength: 3,
                contractTermName: 'Product Term Name',
                termType: CONTRACT_TERM_TYPES.PRODUCT,
            } as ContractTermFormattedPresentational,
            labelId: '12345',
        });
        expect(screen.getByText(/3 products/i)).toBeInTheDocument();
        expect(screen.getByText(/12345/)).toBeInTheDocument();
        expect(
            screen.getByTestId('ContractPresentationalTermName').innerHTML
        ).toEqual('Product Term Name');
        expect(screen.queryByText(/Should Not Appear/)).toBeNull();
    });

    it('builds the link to update terms using updateTerms(contractId, termId, termType)', () => {
        const { rerender } = setup({
            contractId: '123',
            termType: CONTRACT_TERM_TYPES.LABEL,
            contractTermFormattedDataObject: {
                termId: 'ABC',
            } as ContractTermFormattedPresentational,
        });

        const link = screen.getByTestId('termBlockContractEditLink10');
        const expectedHref = updateTerms('123', 'ABC', 'label');
        expect(link).toHaveAttribute('href', expectedHref);

        rerender(
            <MemoryRouter>
                <ContractTermDetailPresentationalHeader
                    contractTermLabelIndex={2}
                    contractTermFormattedDataMapIndex={5}
                    termType={CONTRACT_TERM_TYPES.LABEL}
                    labelId="1234"
                    contractTermFormattedDataObject={
                        {
                            termId: 'C123',
                            termType: CONTRACT_TERM_TYPES.LABEL,
                        } as ContractTermFormattedPresentational
                    }
                    contractId="789"
                    allAttachments={[]}
                />
            </MemoryRouter>
        );

        const newLink = screen.getByTestId('termBlockContractEditLink52');
        // check the new testId as well
        const newHref = updateTerms('789', 'C123', 'label');
        expect(newLink).toHaveAttribute('href', newHref);
    });

    it('renders the edit GlyphIcon with className and size', () => {
        setup();
        const icon = screen.getByTestId('editGlyphIcon');
        expect(icon).toBeInTheDocument();

        // Confirm props from the mock (optional)
        expect(icon).toHaveAttribute(
            'class',
            'ContractTermsConditions-labelInfoBlock-detail-editIcon'
        );
        expect(icon).toHaveAttribute('name', 'edit');
        expect(icon).toHaveAttribute('size', '16');
    });

    it('renders div with termId and link', () => {
        setup({
            contractTermLabelIndex: 1,
            contractTermFormattedDataMapIndex: 2,
        });

        const div = screen.getAllByTestId(
            'labelInfoBlock-detail-header-test'
        )[0];
        expect(div.innerHTML).toContain('10 tracks &nbsp;•&nbsp; TERM-1');

        const link = screen.getByTestId('termBlockContractEditLink21');
        expect(link).toBeInTheDocument();
    });

    it('renders the Sidecar, GlyphIcon, and button with className and size', async () => {
        setup();
        const icon = screen.getByTestId('moreDetailsGlyphIcon');
        expect(icon).toBeInTheDocument();

        expect(icon).toHaveAttribute(
            'class',
            'ContractTermsConditions-labelInfoBlock-detail-moreDetails'
        );
        expect(icon).toHaveAttribute('name', 'moreDetails');
        expect(icon).toHaveAttribute('size', '16');

        const button = screen.getByTestId('moreDetailsButton');
        expect(button).toBeInTheDocument();
        expect(button).toHaveAttribute(
            'class',
            'ContractTermsConditions-labelInfoBlock-detail-sidecarButton btn btn-secondary'
        );

        fireEvent.click(button);
        await waitFor(() => {
            const sidecar = screen.getByTestId('Modal');
            expect(sidecar).toBeInTheDocument();
            expect(sidecar.innerHTML).toContain('Label Term 1');
            const sidecarHeader = screen.getByTestId('SidecarHeader');
            expect(sidecarHeader.innerHTML).toBe('Tracks (2)');
            const listBox = screen.getByTestId('SuiteListBox');
            expect(listBox).toBeInTheDocument();
            const listItemLabels = screen.getAllByTestId(
                'SuiteListView-option-label'
            );
            expect(listItemLabels[0].innerHTML).toBe('isrc1');
            expect(listItemLabels[1].innerHTML).toBe('isrc2');
            const listItemSubtitles = screen.getAllByTestId(
                'SuiteListView-option-subtitle'
            );
            expect(listItemSubtitles[0].innerHTML).toBe('isrc1');
            expect(listItemSubtitles[1].innerHTML).toBe('isrc2');
        });
    });

    it('renders no tracks when there are no attachments', async () => {
        setup({
            contractTermFormattedDataObject: {
                termId: 'TERM-1',
                catalogLength: 0,
                labelIds: ['1234'],
                contractTermName: 'Label Term 1',
                details: [],
                attachments: [],
                termType: CONTRACT_TERM_TYPES.TRACK,
            } as ContractTermFormattedPresentational,
        });

        const subHeaderContainer = screen.getByTestId(
            'labelInfoBlock-detail-subHeaderContainer'
        );
        expect(subHeaderContainer).toHaveTextContent(/0 tracks/i);
    });

    it('renders tooltip when there are no attachments', async () => {
        setup({
            contractTermFormattedDataObject: {
                termId: 'TERM-1',
                catalogLength: 0,
                labelIds: ['1234'],
                contractTermName: 'Label Term 1',
                details: [],
                attachments: [],
                termType: CONTRACT_TERM_TYPES.TRACK,
            } as ContractTermFormattedPresentational,
        });

        const button = screen.getByTestId('moreDetailsButton');
        fireEvent.mouseOver(button);

        await waitFor(() => {
            expect(
                screen.getByText(
                    'There are no tracks associated with this term.'
                )
            ).toBeInTheDocument();
        });
    });
});
