import React, { ReducerState, ReducerAction } from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { ABACUS_PROFILE } from 'src/constants';
import ContractTermConditionsList, {
    ContractTermConditionsList as NamedContractTermConditionsList,
} from 'src/components/contract-terms-form/contract-term-conditions-list';
import { ADD_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: {
    state: ReducerState<any>;
    dispatch: ReducerAction<any>;
}) => (
    <ContractTermContext.Provider value={contextValues}>
        <ContractTermConditionsList />
    </ContractTermContext.Provider>
);

describe('<ContractTermConditionsList>', () => {
    const conditionsList = [
        {
            contractTermConditionId: 100,
            conditions: {
                transactionTypes: [],
                stores: [],
                countries: [],
            },
            priority: 1,
            termRate: '15.15',
        },
    ];
    const contractTermId = 123;

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

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

    afterEach(jest.restoreAllMocks);

    const render = (contextValues: {
        state: ReducerState<any>;
        dispatch: ReducerAction<any>;
    }) => renderInAppContext(componentInContext(contextValues));

    it('renders rows of term condition forms with preloaded data when present', () => {
        const stateWithConditions = {
            ...initialTermState,
            conditions: conditionsList,
            stores,
            transactionTypes,
        };
        const contextValues = {
            state: stateWithConditions,
            dispatch: jest.fn(),
        };
        render(contextValues);
        expect(
            screen.getByDisplayValue(conditionsList[0].termRate)
        ).toBeDefined();
    });

    it('renders draggable rows of term condition when there is more than one condition', () => {
        const secondCondition = { ...conditionsList[0], priority: 2 };
        const conditions = [...conditionsList, secondCondition];
        const stateWithConditions = { ...initialTermState, conditions };
        const contextValues = {
            state: stateWithConditions,
            dispatch: jest.fn(),
        };
        render(contextValues);
        expect(
            screen.getAllByTestId('contractTermConditionRow').length
        ).toEqual(conditions.length);
    });

    it('adds an empty contract term condition form when "+ NEW TERM LINE" is clicked', () => {
        const dispatch = jest.fn();
        const stateWithConditions = {
            ...initialTermState,
            conditions: conditionsList,
            contractTermId,
            stores,
            transactionTypes,
        };
        const contextValues = { state: stateWithConditions, dispatch };
        render(contextValues);

        const addTermLineBtn = screen.getByRole('button', {
            name: '+ NEW TERM LINE',
        });
        fireEvent.click(addTermLineBtn);

        const newCondition = {
            contractTermId,
            priority: conditionsList.length + 1,
        };

        expect(dispatch).toHaveBeenCalledWith({
            type: ADD_CONTRACT_TERM_CONDITION,
            condition: newCondition,
        });
    });

    it('renders the "Copy Conditions From..." link button', () => {
        const contextValues = { state: initialTermState, dispatch: jest.fn() };
        render(contextValues);
        const copyConditionsBtn = screen.getByText('COPY CONDITIONS FROM...');
        expect(copyConditionsBtn).toBeDefined();
    });

    it('opens the "Copy Conditions From..." popup when link button is clicked', () => {
        const contextValues = { state: initialTermState, dispatch: jest.fn() };
        render(contextValues);
        const copyConditionsBtn = screen.getByText('COPY CONDITIONS FROM...');

        fireEvent.click(copyConditionsBtn);

        const popupHeader = screen.getByRole('heading', { level: 3 });
        const copyButton = screen.getByText('Copy');
        expect(popupHeader.textContent).toEqual('Copy Conditions From...');
        expect(copyButton).toBeDefined();
    });
});

describe('ContractTermConditionsList opt-in props', () => {
    const identity = createIdentity({ profileType: ABACUS_PROFILE });
    const state = {
        conditions: [
            {
                contractTermConditionId: null,
                contractTermConditionName: null,
                contractTermId: 't1',
                priority: 1,
                termRate: null,
                conditions: { countries: [], stores: [], transactionTypes: [] },
            },
        ],
        contractTermId: 't1',
        transactionTypes: [],
        transactionTypeGroups: [],
        stores: [],
        deletedConditions: [],
        countryCodes: [],
        errors: [],
    };

    const renderList = (props = {}) =>
        renderInAppContext(
            <ContractTermContext.Provider value={{ state, dispatch: () => {} }}>
                <NamedContractTermConditionsList {...props} />
            </ContractTermContext.Provider>,
            { identity }
        );

    it('defaults to the contract-form labels (no Action column)', () => {
        renderList();
        expect(screen.getByText('+ NEW TERM LINE')).toBeInTheDocument();
        expect(screen.queryByText('Action')).not.toBeInTheDocument();
    });

    it('uses opt-in transfer labels when provided', () => {
        renderList({
            newConditionLabel: '+ NEW CONDITION',
            showActionColumn: true,
        });
        expect(screen.getByText('+ NEW CONDITION')).toBeInTheDocument();
        // "#" heads the priority column; the trash needs no "Action" label.
        expect(screen.getByText('#')).toBeInTheDocument();
        expect(screen.queryByText('Action')).not.toBeInTheDocument();
        expect(screen.queryByText('+ NEW TERM LINE')).not.toBeInTheDocument();
    });

    it('always shows the Action delete control, disabled with a single row', () => {
        renderList({ showActionColumn: true });
        const del = screen.getByTestId('contractTermConditionDeleteIcon');
        expect(del).toBeInTheDocument();
        expect(del).toHaveClass('disableDelete');
    });

    it('keeps the contract-form behavior: no delete control with a single row by default', () => {
        renderList();
        expect(
            screen.queryByTestId('contractTermConditionDeleteIcon')
        ).not.toBeInTheDocument();
    });
});
