import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { EARNINGS_TRANSFER_MODAL_SCREENS } from 'src/apollo/type-constants/contract-earnings-transfer';
import { useContractById } from 'src/apollo/queries/contract';
import { useAccountChange } from 'src/hooks/contract-earnings-transfer/use-account-change';
import { getEarningsTransferBaseColumnDefs } from '../contract-earnings-transfer-config-screen-columns';
import {
    ContractEarningsTransferConfigScreen,
    ContractEarningsTransferConfigScreenProps,
} from '../contract-earnings-transfer-config-screen';
import {
    AbacusEarningsTransferRateTypes,
    AbacusEarningsTransferSources,
    AbacusEarningsTransferTypes,
} from 'src/apollo/definitions/globalTypes';

jest.mock('src/apollo/queries/contract', () => ({
    useContractById: jest.fn(),
}));

jest.mock('src/hooks/contract-earnings-transfer/use-account-change', () => ({
    useAccountChange: jest.fn(),
}));

jest.mock('../contract-earnings-transfer-config-screen-columns', () => ({
    ...jest.requireActual(
        '../contract-earnings-transfer-config-screen-columns'
    ),
    getEarningsTransferBaseColumnDefs: jest.fn(),
}));

// Mock GridTable to simplify testing
jest.mock('@theorchard/suite-components', () => {
    const original = jest.requireActual('@theorchard/suite-components');
    return {
        ...original,
        GridTable: ({ data, columnDefs, testId }: any) => (
            <div data-testid={testId || 'grid-table'}>
                <div data-testid="table-row-count">{data.length}</div>
                <div data-testid="column-defs-count">
                    {columnDefs?.length || 0}
                </div>
            </div>
        ),
    };
});

describe('<ContractEarningsTransferConfigScreen />', () => {
    const defaultProps: ContractEarningsTransferConfigScreenProps = {
        isVisible: true,
        isEditMode: false,
        transferType: AbacusEarningsTransferTypes.OVERRIDE,
        rows: [
            {
                rowId: '1',
                fromContractId: '123',
                toAccountId: 'acc1',
                toContractId: '456',
                transferAmount: '100',
                rateType: undefined,
                input: undefined,
                negative: false,
                active: false,
                useStaticBalance: false,
            },
        ],
        editRow: null,
        onRowChange: jest.fn(),
        onAddRow: jest.fn(),
        onDeleteRow: jest.fn(),
        onResetRows: jest.fn(),
        setModalScreen: jest.fn(),
    };

    beforeEach(() => {
        jest.clearAllMocks();
        (useContractById as jest.Mock).mockReturnValue({
            data: {
                abacusContract: {
                    contractId: '123',
                    contractName: 'Test Contract',
                },
            },
        });
        (useAccountChange as jest.Mock).mockReturnValue(jest.fn());
        (getEarningsTransferBaseColumnDefs as jest.Mock).mockReturnValue([
            { name: 'col1', title: 'Column 1' },
        ]);
    });

    const render = (
        props: Partial<ContractEarningsTransferConfigScreenProps> = {}
    ) =>
        renderInAppContext(
            <ContractEarningsTransferConfigScreen
                {...defaultProps}
                {...props}
            />
        );

    describe('visibility', () => {
        it('renders nothing when isVisible is false', () => {
            render({ isVisible: false });
            expect(screen.queryByText('Transfer Pairs')).toBeNull();
        });

        it('renders the config screen when isVisible is true', () => {
            render();
            expect(screen.getByText('Transfer Pairs')).toBeDefined();
            expect(
                screen.getByText(
                    /Include the contracts below. The From Contract has been prepopulated/
                )
            ).toBeDefined();
        });
    });

    describe('Add More Transfers button', () => {
        it('calls onAddRow when clicked', () => {
            const onAddRow = jest.fn();
            render({ onAddRow });

            fireEvent.click(screen.getByTestId('earningsTransferAddRowButton'));

            expect(onAddRow).toHaveBeenCalled();
        });

        it('is not rendered in edit mode', () => {
            render({ isEditMode: true });

            expect(screen.queryByTestId('earningsTransferAddRowButton')).toBe(
                null
            );
        });
    });

    describe('Processing option toggle', () => {
        it('calls onRowChange for each row when toggled', () => {
            const rows = [
                defaultProps.rows[0],
                { ...defaultProps.rows[0], rowId: '2' },
            ];

            const onRowChange = jest.fn();

            render({ rows, onRowChange });

            const toggle = screen.getByTestId(
                'earningsTransferInParallelToggle'
            );

            fireEvent.click(toggle);

            expect(onRowChange).toHaveBeenCalledTimes(2);
        });

        it('is not rendered in edit mode', () => {
            render({ isEditMode: true });

            expect(
                screen.queryByTestId('earningsTransferInSequenceToggle')
            ).toBeNull();
            expect(
                screen.queryByTestId('earningsTransferInParallelToggle')
            ).toBeNull();
        });
    });

    describe('Negative balance warning', () => {
        it('is rendered under the right conditions', () => {
            const rows = [
                defaultProps.rows[0],
                { ...defaultProps.rows[0], rowId: '2' },
            ];

            render({ rows });

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

        it('is not rendered when processing negative balances', () => {
            const rows = [
                { ...defaultProps.rows[0], negative: true },
                { ...defaultProps.rows[0], rowId: '2' },
            ];

            render({ rows });

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

        it('is not rendered when processing in parallel', () => {
            const rows = [
                defaultProps.rows[0],
                { ...defaultProps.rows[0], rowId: '2' },
            ];

            render({ rows });

            const toggle = screen.getByTestId(
                'earningsTransferInParallelToggle'
            );

            fireEvent.click(toggle);

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

        it('is not rendered for only one row', () => {
            render();

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

    describe('Total percentage error', () => {
        it('is not rendered when the total percentage is not above 100%', () => {
            const rows = [
                {
                    rowId: '1',
                    fromContractId: '123',
                    toAccountId: 'acc1',
                    toContractId: '456',
                    transferAmount: '60',
                    rateType: AbacusEarningsTransferRateTypes.PERCENT,
                    input: AbacusEarningsTransferSources.CLOSING_BALANCE,
                    negative: false,
                    active: true,
                    useStaticBalance: false,
                },
                {
                    rowId: '2',
                    fromContractId: '123',
                    toAccountId: 'acc2',
                    toContractId: '789',
                    transferAmount: '10',
                    rateType: AbacusEarningsTransferRateTypes.PERCENT,
                    input: AbacusEarningsTransferSources.CLOSING_BALANCE,
                    negative: false,
                    active: true,
                    useStaticBalance: false,
                },
            ];

            render({ rows });

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

        it('is rendered when the total percentage is above 100%', () => {
            const rows = [
                {
                    rowId: '1',
                    fromContractId: '123',
                    toAccountId: 'acc1',
                    toContractId: '456',
                    transferAmount: '60',
                    rateType: AbacusEarningsTransferRateTypes.PERCENT,
                    input: AbacusEarningsTransferSources.CLOSING_BALANCE,
                    negative: false,
                    active: true,
                    useStaticBalance: false,
                },
                {
                    rowId: '2',
                    fromContractId: '123',
                    toAccountId: 'acc2',
                    toContractId: '789',
                    transferAmount: '60',
                    rateType: AbacusEarningsTransferRateTypes.PERCENT,
                    input: AbacusEarningsTransferSources.CLOSING_BALANCE,
                    negative: false,
                    active: true,
                    useStaticBalance: false,
                },
            ];

            render({ rows });

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

    describe('Back button', () => {
        it('opens modal', () => {
            const setModalScreen = jest.fn();
            render({ setModalScreen });

            fireEvent.click(screen.getByTestId('earningsTransferBackButton'));

            expect(
                screen.getByText('Confirm Transfer Type Change')
            ).toBeDefined();
        });

        it('calls setModalScreen with SELECT_TYPE when clicked', () => {
            const setModalScreen = jest.fn();
            render({ setModalScreen });

            fireEvent.click(screen.getByTestId('earningsTransferBackButton'));
            fireEvent.click(screen.getByText('Change transfer type'));

            expect(setModalScreen).toHaveBeenCalledWith(
                EARNINGS_TRANSFER_MODAL_SCREENS.SELECT_TYPE
            );
        });
    });

    describe('Table', () => {
        it('renders the GridTable with correct number of rows', () => {
            render({
                rows: [
                    { rowId: '1', fromContractId: '123' } as any,
                    { rowId: '2', fromContractId: '123' } as any,
                ],
            });

            expect(screen.getByTestId('table-row-count')).toHaveTextContent(
                '2'
            );
        });
    });
});
