import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as suiteFrontend from '@theorchard/suite-frontend';
import * as productByUpcResponse from 'src/__fixtures__/graphql/product-by-upc-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 ProductSearchableSelect from 'src/components/shared/product-searchable-select';
import type { GetProductByUpcQuery } from 'src/apollo/queries/product-search/__generated__/get-product-by-upc';
import type { SearchProductsAbacusQuery } from 'src/apollo/queries/product-search/__generated__/get-products';

jest.mock('@theorchard/suite-frontend', () => ({
    ...jest.requireActual('@theorchard/suite-frontend'),
    useFeatureFlag: jest.fn(),
}));

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

describe('<ProductSearchableSelect/>', () => {
    const productUpc = '1111122222';
    const getProductByUpc = jest.fn().mockReturnValue(productByUpcResponse);
    const getContractsTermsMock = jest.fn().mockReturnValue([]);
    const props = {
        accountId: '1',
        contractTermId: '1',
        contractId: '1234',
        onChange: jest.fn(),
        productUpcs: [productUpc],
        labelIds: [2, 4],
        setErrors: jest.fn(),
    };

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

    afterEach(jest.restoreAllMocks);
    beforeEach(() => {
        (suiteFrontend.useFeatureFlag as jest.Mock).mockReturnValue(true);
        jest.spyOn(productQuery, 'useProductSearch').mockReturnValue(
            async () =>
                await Promise.resolve(
                    productSearchResponse.searchProducts.products as Products
                )
        );
        jest.spyOn(productQuery, 'useProductByUpc').mockReturnValue({
            data: productByUpcResponse as GetProductByUpcQuery,
            loading: false,
            getProductByUpc,
        });
        jest.spyOn(
            contractTermQuery,
            'useContractTermsByAccount'
        ).mockReturnValue({
            data: { abacusContractTermsByAccount: [] },
            loading: false,
            getContractsTerms: getContractsTermsMock,
        });
    });

    it('renders', () => {
        const { container } = render();
        expect(container).toBeDefined();
        expect(screen.getByTestId('searchableSelectListTestid')).toBeTruthy();
        expect(getProductByUpc).toHaveBeenLastCalledWith(productUpc);
    });

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

    it('on input blur, call useContractTermsByAccount', async () => {
        render();
        const productSelect = screen.getByRole('combobox');
        fireEvent.change(productSelect, { target: { value: 'Test' } });
        fireEvent.keyDown(productSelect, {
            key: 'Enter',
            code: 'Enter',
            charCode: 13,
        });
        fireEvent.blur(productSelect);
        await waitFor(() => {
            expect(getContractsTermsMock).toHaveBeenCalledWith(
                '1',
                ['1111122222'],
                'product'
            );
        });
    });
});
