import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as productsByUpcsResponse from 'src/__fixtures__/graphql/products-by-upcs-response.json';
import * as productSearchResponse from 'src/__fixtures__/graphql/product-search-response.json';
import * as contractTermQuery from 'src/apollo/queries/contract-term';
import * as productQuery from 'src/apollo/queries/product-search';
import ProductMultiSelect from 'src/components/shared/product-multiselect';
import type { SearchProductsAbacusQuery } from 'src/apollo/queries/product-search/__generated__/get-products';

type Products = NonNullable<
    SearchProductsAbacusQuery['searchProducts']
>['products'];

describe('<ProductMultiSelect/>', () => {
    const productUpc = '1111122222';
    const getContractsTermsMock = jest.fn().mockReturnValue([]);
    const props = {
        accountId: '1',
        contractTermId: '1',
        contractTerms: [],
        onChange: jest.fn(),
        productUpcs: [productUpc],
        labelIds: [2, 4],
        setErrors: jest.fn(),
    };
    const fakeProducts = (productsByUpcsResponse as any)
        .productByUpcs as Array<{ upc: string; productName: string }>;

    const render = () => renderInAppContext(<ProductMultiSelect {...props} />);

    afterEach(jest.restoreAllMocks);
    beforeEach(() => {
        jest.spyOn(productQuery, 'useProductSearch').mockReturnValue(
            async () =>
                await Promise.resolve(
                    productSearchResponse.searchProducts.products as Products
                )
        );

        const getProductsByUpcsMock = jest
            .fn()
            .mockResolvedValue({ data: { getProductsByUpcs: fakeProducts } });
        jest.spyOn(productQuery, 'useProductsByUpcs').mockReturnValue({
            data: { productByUpcs: fakeProducts },
            getProductsByUpcs: getProductsByUpcsMock,
            loading: false,
        });
        jest.spyOn(
            contractTermQuery,
            'useContractTermsByAccount'
        ).mockReturnValue({
            data: { abacusContractTermsByAccount: [] },
            loading: false,
            getContractsTerms: getContractsTermsMock,
        });
    });

    it('renders', () => {
        render();
        expect(screen.getByTestId('SuiteMultiSelect')).toBeDefined();
        expect(productQuery.useProductsByUpcs).toHaveBeenCalled();
    });

    it('searches products on input change', async () => {
        render();
        const productSelect = screen.getByRole('combobox', { hidden: true });
        fireEvent.click(productSelect);
        const productInput = screen.getByTestId('SuiteListViewFilterInput')!;
        fireEvent.change(productInput, { target: { value: 'Test' } });
        await waitFor(() => {
            expect(
                screen.getByText('Test Product 1-193483764306')
            ).toBeDefined();
            expect(
                screen.getByText('Test Product 2-192562874172')
            ).toBeDefined();
        });
    });

    it('on select value, call useContractTermsByAccount', async () => {
        render();
        const productSelect = screen.getByRole('combobox', { hidden: true });
        fireEvent.click(productSelect);
        const productInput = screen.getByTestId('SuiteListViewFilterInput')!;
        fireEvent.change(productInput, { target: { value: 'Test' } });
        await waitFor(() => {
            expect(
                screen.getByText('Test Product 1-193483764306')
            ).toBeDefined();
            expect(
                screen.getByText('Test Product 2-192562874172')
            ).toBeDefined();
        });
        const option = screen.getByText('Test Product 1-193483764306');
        fireEvent.click(option);
        expect(getContractsTermsMock).not.toHaveBeenCalled();
        fireEvent.click(document);
        const expectedUpcs = [...fakeProducts.map(p => p.upc), '193483764306'];
        await waitFor(() => {
            expect(getContractsTermsMock).toHaveBeenCalledWith(
                props.accountId,
                expectedUpcs,
                'product'
            );
        });
    });
});
