import * as toast from '@theorchard/suite-components';
import * as earningsTransferMutation from 'src/apollo/mutations/contract-earnings-transfer';
import {
    AbacusEarningsTransferRateTypes,
    AbacusEarningsTransferSources,
    AbacusEarningsTransferTypes,
} from 'src/apollo/definitions/globalTypes';
import { useCreateHandler } from '../create-contract-earnings-transfer';
import { type TransferRow } from 'src/types/abacus-contract-earnings-transfer';

describe('useCreateHandler', () => {
    let mockCreateEarningsTransfer: jest.Mock;
    let createEarningsTransferSpy: jest.SpyInstance;
    let useToastSpy: jest.SpyInstance;
    let toastFn: jest.Mock;

    beforeEach(() => {
        mockCreateEarningsTransfer = jest.fn().mockResolvedValue({});

        createEarningsTransferSpy = jest
            .spyOn(earningsTransferMutation, 'useCreateEarningsTransfer')
            .mockReturnValue(mockCreateEarningsTransfer);

        toastFn = jest.fn();
        useToastSpy = jest.spyOn(toast, 'useToast').mockReturnValue(toastFn);
    });

    afterEach(jest.restoreAllMocks);

    const makeRow = (overrides: Partial<TransferRow> = {}): TransferRow => ({
        rowId: 'row-1',
        fromContractId: 'contract-10',
        toAccountId: 'account-20',
        toContractId: 'contract-99',
        rateType: AbacusEarningsTransferRateTypes.PERCENT,
        transferAmount: '50',
        input: AbacusEarningsTransferSources.CLOSING_BALANCE,
        negative: false,
        active: true,
        useStaticBalance: false,
        ...overrides,
    });

    it('calls mutation with correctly mapped variables for a single row', async () => {
        const saveHandler = useCreateHandler('contract-10');
        const row = makeRow();

        await saveHandler(AbacusEarningsTransferTypes.TRANSFER, [row]);

        expect(createEarningsTransferSpy).toHaveBeenCalledWith('contract-10');
        expect(mockCreateEarningsTransfer).toHaveBeenCalledWith({
            variables: {
                earningsTransfer: [
                    {
                        fromContractId: 'contract-10',
                        toContractId: 'contract-99',
                        transferType: AbacusEarningsTransferTypes.TRANSFER,
                        transferAmount: 50,
                        rateType: AbacusEarningsTransferRateTypes.PERCENT,
                        input: AbacusEarningsTransferSources.CLOSING_BALANCE,
                        active: true,
                        negative: false,
                        useStaticBalance: false,
                    },
                ],
            },
        });
    });

    it('parses transferAmount string to float', async () => {
        const saveHandler = useCreateHandler('contract-10');
        const row = makeRow({ transferAmount: '12.5' });

        await saveHandler(AbacusEarningsTransferTypes.RECLASS, [row]);

        expect(mockCreateEarningsTransfer).toHaveBeenCalledWith(
            expect.objectContaining({
                variables: expect.objectContaining({
                    earningsTransfer: expect.arrayContaining([
                        expect.objectContaining({ transferAmount: 12.5 }),
                    ]),
                }),
            })
        );
    });

    it('shows singular toast message when saving one row', async () => {
        const saveHandler = useCreateHandler('contract-10');

        await saveHandler(AbacusEarningsTransferTypes.TRANSFER, [makeRow()]);

        expect(useToastSpy).toHaveBeenCalled();
        expect(toastFn).toHaveBeenCalledWith(
            'Transfer of earnings has been successfully added.'
        );
    });

    it('shows plural toast message when saving multiple rows', async () => {
        const saveHandler = useCreateHandler('contract-10');
        const rows = [
            makeRow(),
            makeRow({ rowId: 'row-2' }),
            makeRow({ rowId: 'row-3' }),
        ];

        await saveHandler(AbacusEarningsTransferTypes.TRANSFER, rows);

        expect(toastFn).toHaveBeenCalledWith(
            '3 transfers of earnings have been successfully added.'
        );
    });

    it('maps multiple rows with correct transferType for each', async () => {
        const saveHandler = useCreateHandler('contract-10');
        const rows = [
            makeRow({
                transferAmount: '25',
                rateType: AbacusEarningsTransferRateTypes.PERCENT,
            }),
            makeRow({
                rowId: 'row-2',
                toContractId: 'contract-55',
                transferAmount: '1000',
                rateType: AbacusEarningsTransferRateTypes.FLAT_RATE,
                input: AbacusEarningsTransferSources.GROSS_REVENUE,
                negative: true,
                active: false,
            }),
        ];

        await saveHandler(AbacusEarningsTransferTypes.RECLASS, rows);

        expect(mockCreateEarningsTransfer).toHaveBeenCalledWith({
            variables: {
                earningsTransfer: [
                    expect.objectContaining({
                        transferType: AbacusEarningsTransferTypes.RECLASS,
                        transferAmount: 25,
                    }),
                    expect.objectContaining({
                        toContractId: 'contract-55',
                        transferType: AbacusEarningsTransferTypes.RECLASS,
                        transferAmount: 1000,
                        rateType: AbacusEarningsTransferRateTypes.FLAT_RATE,
                        input: AbacusEarningsTransferSources.GROSS_REVENUE,
                        negative: true,
                        active: false,
                    }),
                ],
            },
        });
    });
});
