import React from 'react';
import { fireEvent, screen, within } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import DragAndDrop from 'src/components/shared/drag-and-drop';
import ContractTermConditionForm, {
    type ContractTermConditionFormProps,
} from 'src/components/contract-terms-form/contract-term-condition-form';
import {
    DELETE_TERM_CONDITION,
    SET_CONTRACT_TERM_CONDITION,
} from 'src/constants';
import { ContractTermContext } from 'src/contexts/contract-term-context';
import { initialTermState } from 'src/reducers/contract-term/contract-term-reducer';

const componentInContext = (
    contextValues: any,
    props: ContractTermConditionFormProps
) => (
    <ContractTermContext.Provider value={contextValues}>
        <DragAndDrop items={[{ id: props.condition.priority }]}>
            <ContractTermConditionForm {...props} />
        </DragAndDrop>
    </ContractTermContext.Provider>
);

describe('<ContractTermConditionForm> tests', () => {
    const render = (
        contextValues: any,
        props: ContractTermConditionFormProps
    ) => renderInAppContext(componentInContext(contextValues, props));

    const condition = {
        conditions: {
            countries: [],
            stores: [],
            transactionTypes: [],
        },
        contractTermConditionId: null,
        priority: 1,
        termRate: '',
        contractTermConditionName: '',
        contractTermId: '',
    };

    let dispatch: jest.Mock;
    const dragAndDropCondition = jest.fn();
    const index = 0;
    const props: ContractTermConditionFormProps = {
        condition,
        dragAndDropCondition,
        index,
    };

    const stores = [
        { label: '121 Music', value: 1 },
        { label: 'Spotify', value: 2 },
    ];

    const transactionTypes = [
        { label: 'Ad-Disabled Video Streams', value: '1' },
        { label: 'Cloud Match Units', value: '2' },
    ];

    const state = {
        ...initialTermState,
        conditions: [condition],
        stores,
        transactionTypes,
    };

    beforeEach(() => (dispatch = jest.fn()));

    it('renders with null conditions', () => {
        const termCondition = {
            conditions: {
                countries: null,
                stores: null,
                transactionTypes: null,
            },
            contractTermConditionId: null,
            priority: 1,
            termRate: '',
        };
        const termState = { ...initialTermState, conditions: [termCondition] };
        const contextValues = { state: termState, dispatch };
        const { container } = render(contextValues, props);
        expect(container).toBeDefined();
    });

    it('is not draggable when contract term condition is the only condition', () => {
        const contextValues = { state, dispatch };
        render(contextValues, props);

        expect(screen.queryByTestId('DragGlyphIcon')).toBeNull();
    });

    it('is draggable when contract term condition is one of many conditions', () => {
        const draggableProps = { ...props, isDraggable: true };
        const contextValues = { state, dispatch };
        render(contextValues, draggableProps);

        expect(screen.getByTestId('DragGlyphIcon')).toBeDefined();
    });

    it('is not deletable when contract term condition is the only condition', () => {
        const contextValues = { state, dispatch };
        render(contextValues, props);

        expect(
            screen.queryByTestId('contractTermConditionDeleteIcon')
        ).toBeNull();
    });

    it('dispatches condition update when transaction types is selected', async () => {
        const contextValues = { state, dispatch };
        render(contextValues, props);

        const selector = screen.getByTestId('TransactionTypeMultiSelect');
        fireEvent.click(
            within(selector).getByRole('combobox', { hidden: true })
        );
        const txnTypeSelect = screen.getByTestId('SuiteListViewFilterInput');
        expect(txnTypeSelect).toBeDefined();

        const txnTypeName = transactionTypes[0]['label'];
        const txnTypeId = transactionTypes[0]['value'];

        const option = screen
            .getByText(txnTypeName, {
                selector: '.SuiteListView .SuiteListView-option-label',
            })
            .closest('.SuiteListView-option');
        fireEvent.click(option);

        expect(dispatch).toHaveBeenCalledWith({
            type: SET_CONTRACT_TERM_CONDITION,
            index,
            name: 'transactionTypes',
            value: [txnTypeId],
        });
    });

    it('dispatches condition update when store is selected', async () => {
        const contextValues = { state, dispatch };
        render(contextValues, props);

        const selector = screen.getByTestId('ServiceMultiSelect');
        fireEvent.click(
            within(selector).getByRole('combobox', { hidden: true })
        );
        const storeSelect = screen.getByTestId('SuiteListViewFilterInput');
        expect(storeSelect).toBeDefined();

        const storeId = stores[0].value;
        const storeName = stores[0].label;

        const option = screen
            .getByText(storeName, {
                selector: '.SuiteListView .SuiteListView-option-label',
            })
            .closest('.SuiteListView-option');
        fireEvent.click(option);

        expect(dispatch).toHaveBeenCalledWith({
            type: SET_CONTRACT_TERM_CONDITION,
            index,
            name: 'stores',
            value: [storeId],
        });
    });

    it('dispatches condition update when country is selected', async () => {
        const contextValues = { state, dispatch };
        render(contextValues, props);

        const selector = screen.getByTestId('SuiteMarketSelector');
        fireEvent.click(
            within(selector).getByRole('combobox', { hidden: true })
        );
        const countrySelect = screen.getByTestId('SuiteListViewFilterInput');
        expect(countrySelect).toBeDefined();

        const option =
            screen
                .getByText('United States', {
                    selector: '.SuiteListView .SuiteListView-option-label',
                })
                .closest('.SuiteListView-option') ?? new Element();
        fireEvent.click(option);

        expect(dispatch).toHaveBeenCalledWith({
            type: SET_CONTRACT_TERM_CONDITION,
            index,
            name: 'countries',
            value: ['USA'],
        });
    });

    it('dispatches condition update when term rate is changed', () => {
        const contextValues = { state, dispatch };
        render(contextValues, props);

        const termRate = '55.55';
        const termRateInput = screen.getByTestId('termRate');
        fireEvent.change(termRateInput, { target: { value: termRate } });

        expect(dispatch).toHaveBeenCalledWith({
            type: SET_CONTRACT_TERM_CONDITION,
            index,
            name: 'termRate',
            value: termRate,
        });
    });

    it('dispatches DELETE_TERM_CONDITION on click of delete icon', () => {
        const termState = {
            ...initialTermState,
            conditions: [condition, condition],
        };

        const contextValues = { state: termState, dispatch };
        render(contextValues, props);
        const deleteButtons = screen.getAllByTestId(
            'contractTermConditionDeleteIcon'
        );
        fireEvent.click(deleteButtons[0]);

        expect(dispatch).toHaveBeenCalledWith({
            type: DELETE_TERM_CONDITION,
            termCondition: condition,
            termConditionIndex: 0,
        });
    });
});
