import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { contractTerm } from 'src/__fixtures__/graphql/contract-term';
import * as storeList from 'src/__fixtures__/graphql/store-list-response.json';
import * as transactionTypeList from 'src/__fixtures__/graphql/transaction-types-response.json';
import * as updatedContractTermCondition from 'src/__fixtures__/graphql/update-contract-term-condition-response.json';
import * as updatedProductException from 'src/__fixtures__/graphql/update-product-exception-response.json';
import * as contractTermMutation from 'src/apollo/mutations/contract-term';
import * as contractTermConditionMutation from 'src/apollo/mutations/contract-term-condition';
import * as contractTermQuery from 'src/apollo/queries/contract-term';
import * as storesQuery from 'src/apollo/queries/stores';
import * as transactionTypeQuery from 'src/apollo/queries/transaction-types';
import ContractTerms from 'src/components/contract-terms-form/contract-terms';
import * as contractTermValidation from 'src/utils/form-validations/contract-term-form-validation';
import type { GetStoresQuery } from 'src/apollo/queries/__generated__/stores';
import type { GetTransactionTypesQuery } from 'src/apollo/queries/transaction-types/__generated__/transaction-types';

jest.mock('react-router-dom', () => ({
    ...jest.requireActual('react-router-dom'),
    useParams: jest.fn().mockReturnValue({
        contractId: '123',
        contractTermId: '555',
        termType: 'product-exception',
    }),
}));

describe('<ContractTerms> edit tests', () => {
    const updateProductException = jest
        .fn()
        .mockResolvedValue(updatedProductException);
    const updateProductExceptionConditions = jest
        .fn()
        .mockResolvedValue(updatedContractTermCondition);
    const render = () => renderInAppContext(<ContractTerms />);

    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        jest.spyOn(
            contractTermMutation,
            'useUpdateContractTerm'
        ).mockReturnValue(updateProductException);
        jest.spyOn(
            contractTermConditionMutation,
            'useUpdateContractTermConditions'
        ).mockReturnValue(updateProductExceptionConditions);
        jest.spyOn(storesQuery, 'useStoreList').mockReturnValue({
            data: storeList as GetStoresQuery,
            loading: false,
        });
        jest.spyOn(transactionTypeQuery, 'useTransactionTypes').mockReturnValue(
            {
                data: transactionTypeList as GetTransactionTypesQuery,
                loading: false,
            }
        );
    });

    it('renders <ContractTerms>', () => {
        render();
        expect(screen.getByText('Product Exception')).toBeDefined();

        const saveButton = screen.getByRole('button', { name: 'Save' });
        expect(saveButton).toBeDefined();

        const cancelButton = screen.getByRole('button', { name: 'Cancel' });
        expect(cancelButton).toBeDefined();
    });

    it('displays validation error when present', async () => {
        const formValidationSpy = jest
            .spyOn(contractTermValidation, 'contractTermFormValidation')
            .mockReturnValue(['Say please']);
        render();

        const saveButton = screen.getByRole('button', { name: 'Save' });
        fireEvent.click(saveButton);

        await waitFor(() => {
            expect(formValidationSpy).toHaveBeenCalled();
        });

        expect(screen.getByText('Say please')).toBeDefined();
    });

    it('updates product exception and conditions', async () => {
        jest.spyOn(
            contractTermValidation,
            'contractTermFormValidation'
        ).mockReturnValue([]);
        jest.spyOn(
            contractTermValidation,
            'areBaseTermLabelsRemoved'
        ).mockReturnValue(false);
        const mockContractTerm = {
            data: {
                abacusContractTerm: {
                    ...contractTerm?.abacusContractTerm,
                    attachmentsRelations: { labelIds: ['1234'], upcs: null },
                    isBaseTerm: false,
                    termType: 'product',
                },
            },
            error: undefined,
            loading: false,
        };
        jest.spyOn(contractTermQuery, 'useContractTerm').mockReturnValue(
            mockContractTerm
        );
        render();

        const saveButton = screen.getByRole('button', { name: 'Save' });
        fireEvent.click(saveButton);

        await waitFor(() => {
            expect(updateProductException).toHaveBeenCalledWith({
                variables: {
                    attachments: ['32486'],
                    attachmentsRelations: { labelIds: ['1234'] },
                    contractId: '123',
                    contractTermId: '1',
                    isBaseTerm: false,
                    termType: 'product',
                },
            });
            expect(updateProductExceptionConditions).toHaveBeenCalled();
        });
    });
});
