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 { useUpdateHandler } from '../update-contract-earnings-transfer';
import { type TransferRow } from 'src/types/abacus-contract-earnings-transfer';

describe('useUpdateHandler', () => {
    let mockUpdateEarningsTransfer: jest.Mock;
    let updateEarningsTransferSpy: jest.SpyInstance;
    let useToastSpy: jest.SpyInstance;
    let toastFn: jest.Mock;

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

        updateEarningsTransferSpy = jest
            .spyOn(earningsTransferMutation, 'useUpdateEarningsTransfer')
            .mockReturnValue(mockUpdateEarningsTransfer);

        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', async () => {
        const saveHandler = useUpdateHandler('contract-10');
        const row = makeRow();

        await saveHandler(
            'transfer-10',
            AbacusEarningsTransferTypes.TRANSFER,
            row
        );

        expect(updateEarningsTransferSpy).toHaveBeenCalledWith('contract-10');
        expect(mockUpdateEarningsTransfer).toHaveBeenCalledWith({
            variables: {
                earningsTransfer: [
                    {
                        earningsTransferId: 'transfer-10',
                        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 = useUpdateHandler('contract-10');
        const row = makeRow({ transferAmount: '12.5' });

        await saveHandler(
            'transfer-10',
            AbacusEarningsTransferTypes.RECLASS,
            row
        );

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

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

        await saveHandler(
            'transfer-10',
            AbacusEarningsTransferTypes.TRANSFER,
            makeRow()
        );

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