import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import {
    mockUseProductSearch,
    mockUseTrackSearchByLabelIds,
} from 'src/__fixtures__/graphql/contract-term-hooks';
import { mockProductSearch } from 'src/__fixtures__/graphql/contract-term-products';
import { mockTrackSearch } from 'src/__fixtures__/graphql/contract-term-tracks';
import {
    ContractTermsDistroAttachmentsSelect,
    ContractTermsDistroAttachmentsSelectProps,
} from 'src/components/contract-terms-refactored/contract-terms-distro-attachments-select';

describe('<ContractTermsDistroAttachmentsSelect />', () => {
    const defaultProps: ContractTermsDistroAttachmentsSelectProps = {
        labelId: 123,
        termType: 'track',
        onOptionsChange: jest.fn(),
        errors: {},
        initialOptions: [],
    };

    const render = (
        props: Partial<ContractTermsDistroAttachmentsSelectProps> = {}
    ) =>
        renderInAppContext(
            <ContractTermsDistroAttachmentsSelect
                {...{ ...defaultProps, ...props }}
            />
        );

    beforeEach(() => {
        jest.clearAllMocks();
    });

    it('renders the correct label for track termType', () => {
        render();
        expect(screen.getByText('Tracks')).toBeInTheDocument();
        expect(screen.getByText('(Optional)')).toBeInTheDocument();
    });

    it('renders the correct label for product termType', () => {
        render({ termType: 'product' });
        expect(screen.getByText('Products')).toBeInTheDocument();
        expect(screen.getByText('(Optional)')).toBeInTheDocument();
    });

    it('disables MultiSelect when labelId is undefined', async () => {
        render({ labelId: undefined });
        const multiSelect = await screen.findByTestId('SuiteSelectInput');
        expect(multiSelect).toHaveClass('disabled');
    });

    it('loads and displays tracks when termType is "track"', async () => {
        render({
            termType: 'product',
            initialOptions: [
                { name: 'Track C', artistName: 'Artist A', value: 'ISRC789' },
            ],
        });
        const expandButton = await screen.findByTestId(
            'SuiteListViewExpandButton'
        );
        fireEvent.click(expandButton);
        await waitFor(() => {
            expect(
                screen.getAllByText('Track C - ISRC789')[0]
            ).toBeInTheDocument();
        });
    });

    it('loads and displays products when termType is "product"', async () => {
        render({
            termType: 'product',
            initialOptions: [
                {
                    name: 'Product C',
                    artistName: 'Artist C',
                    value: '1982039393',
                },
            ],
        });

        const expandButton = await screen.findByTestId(
            'SuiteListViewExpandButton'
        );
        fireEvent.click(expandButton);
        await waitFor(() => {
            expect(
                screen.getAllByText('Product C - 1982039393')[0]
            ).toBeInTheDocument();
        });
    });

    it('shows new options when searching for tracks', async () => {
        mockUseTrackSearchByLabelIds(mockTrackSearch);

        render();

        const expandButton = await screen.findByTestId(
            'SuiteListViewExpandButton'
        );
        fireEvent.click(expandButton);

        const input = screen.getByTestId('SuiteListViewFilterInput');
        fireEvent.change(input, { target: { value: 'Track' } });

        await waitFor(() => {
            const results = screen.getAllByTestId('SuiteListView-option-label');
            expect(results.length).toBeGreaterThan(0);
        });
        const results = screen.getAllByTestId('SuiteListView-option-label');
        expect(results[0].innerHTML).toBe('Track A - ISRC123');
        expect(results[1].innerHTML).toBe('Track B - ISRC456');
    });

    it('shows new options when searching for products', async () => {
        mockUseProductSearch(mockProductSearch);

        render({ termType: 'product' });

        const expandButton = await screen.findByTestId(
            'SuiteListViewExpandButton'
        );
        fireEvent.click(expandButton);

        const input = screen.getByTestId('SuiteListViewFilterInput');
        fireEvent.change(input, { target: { value: 'Product' } });

        let results: HTMLElement[] = [];
        await waitFor(() => {
            results = screen.getAllByTestId('SuiteListView-option-label');
            expect(results.length).toBeGreaterThan(0);
        });
        expect(results[0].innerHTML).toBe('Product A - UPC123');
        expect(results[1].innerHTML).toBe('Product B - UPC456');
    });

    it('calls onOptionsChange with selected ISRCs', async () => {
        const onOptionsChange = jest.fn();
        mockUseTrackSearchByLabelIds(mockTrackSearch);

        render({ onOptionsChange });

        const expandButton = await screen.findByTestId(
            'SuiteListViewExpandButton'
        );
        fireEvent.click(expandButton);
        const input = screen.getByTestId('SuiteListViewFilterInput');
        fireEvent.change(input, { target: { value: 'Track' } });
        const option = await screen.findByText('Track A - ISRC123');
        fireEvent.click(option);

        await waitFor(() => {
            expect(onOptionsChange).toHaveBeenCalledWith(['ISRC123']);
        });
    });

    it('handles request failure and sets options to empty', async () => {
        console.error = jest.fn();

        const trackSearchMock = mockUseTrackSearchByLabelIds();
        trackSearchMock.mockRejectedValue(new Error('API Error'));

        const errors = { attachments: 'Failed to load' };
        render({ errors });

        const expandButton = await screen.findByTestId(
            'SuiteListViewExpandButton'
        );
        fireEvent.click(expandButton);

        await waitFor(() => {
            expect(
                screen.queryByText('Track A - ISRC123')
            ).not.toBeInTheDocument();
        });

        await waitFor(() => {
            expect(
                screen.queryByText('Track B - ISRC456')
            ).not.toBeInTheDocument();
        });

        expect(errors.attachments).toContain('Failed to load');
    });
});
