import React from 'react';
import { ApolloError } from '@apollo/client';
import { fireEvent, waitFor, within } from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { MemoryRouter, Route } from 'react-router-dom';
import * as collaboratorMutations from 'src/apollo/mutations/collaborators';
import * as replaceDpPaymentsMutationModule from 'src/apollo/mutations/replace-dp-payments';
import * as submitDpPaymentsMutationModule from 'src/apollo/mutations/submit-dp-payments';
import { DpPayoneerPaymentStatus } from 'src/apollo/definitions/globalTypes';
import { CollaboratorsDpPaymentsQuery } from 'src/apollo/queries/collaborators/__generated__/dp-payments';
import { CollaboratorsPeriodDetailQuery } from 'src/apollo/queries/collaborators/__generated__/period-detail';
import * as dpPaymentsQueryModule from 'src/apollo/queries/collaborators/dp-payments';
import * as periodDetailQueryModule from 'src/apollo/queries/collaborators/period-detail';
import { CollaboratorsReportRun } from 'src/apollo/queries/collaborators/period-detail';
import { USER_FEATURES } from 'src/constants';
import { CollaboratorsPeriodDetail } from '../collaborators-period-detail';

const mockReportRun: CollaboratorsReportRun = {
    __typename: 'CollaboratorReportRun',
    id: '2',
    requestedDateTime: '2025-05-01T00:00:00Z',
    transactionAggregations: {
        currencyAgnosticTotal: 1234,
        nonZeroCount: 250,
        totalCount: 225,
        completedDate: '2025-05-02T00:00:00Z',
    },
    contractSubtotalAggregations: {
        currencyAgnosticTotalAmount: 1234,
        totalCount: 1,
    },
};

const baseStatementPeriod = {
    __typename: 'AbacusStatementPeriod' as const,
    collaboratorsPaymentFeeTransactions: {
        __typename: 'CollaboratorTransactionResults' as const,
        nominalTotalAmount: 0,
        totalCount: 0,
        transactions: [],
    },
    collaboratorsWhtAllocationTransactions: {
        __typename: 'CollaboratorTransactionResults' as const,
        nominalTotalAmount: 0,
        totalCount: 0,
    },
    collaboratorsDirectPaymentBalances: {
        __typename: 'CollaboratorsDirectPaymentBalancesResults' as const,
        totalCount: 0,
        currencyAgnosticTotalAmount: 0,
    },
    collaboratorsPaymentApprovals: {
        __typename: 'CollaboratorTransactionResults' as const,
        nominalTotalAmount: 0,
        totalCount: 0,
    },
    collaboratorsDirectPaymentTransactions: {
        __typename: 'CollaboratorsDirectPaymentTransactionResults' as const,
        nominalTotalAmount: 0,
        totalCount: 0,
    },
};

const currentPeriodMock: CollaboratorsPeriodDetailQuery = {
    abacusStatementPeriod: {
        ...baseStatementPeriod,
        statementPeriodStatus: 'current',
        statementPeriodId: '322',
        statementPeriodName: 'October 2025',
        collaboratorsReportRun: null,
        collaboratorsRevenueAdjustments: {
            totalCount: 0,
            currencyAgnosticTotalAmount: 0,
        },
        collaboratorsWhtAdjustments: {
            totalCount: 0,
            currencyAgnosticTotalAmount: 0,
        },
    },
};

const currentPeriodWithRunMock: CollaboratorsPeriodDetailQuery = {
    abacusStatementPeriod: {
        ...baseStatementPeriod,
        statementPeriodStatus: 'current',
        statementPeriodId: '322',
        statementPeriodName: 'October 2025',
        collaboratorsReportRun: mockReportRun,
        collaboratorsRevenueAdjustments: {
            totalCount: 5,
            currencyAgnosticTotalAmount: 200,
        },
        collaboratorsWhtAdjustments: {
            totalCount: 3,
            currencyAgnosticTotalAmount: 100,
        },
    },
};

const pastPeriodMock: CollaboratorsPeriodDetailQuery = {
    abacusStatementPeriod: {
        ...baseStatementPeriod,
        statementPeriodStatus: 'CLOSED',
        statementPeriodId: '321',
        statementPeriodName: 'September 2025',
        collaboratorsReportRun: mockReportRun,
        collaboratorsRevenueAdjustments: {
            totalCount: 15,
            currencyAgnosticTotalAmount: 255,
        },
        collaboratorsWhtAdjustments: {
            totalCount: 11,
            currencyAgnosticTotalAmount: 45,
        },
    },
};

const pastPeriodWithPaymentsMock: CollaboratorsPeriodDetailQuery = {
    abacusStatementPeriod: {
        ...baseStatementPeriod,
        statementPeriodStatus: 'CLOSED',
        statementPeriodId: '321',
        statementPeriodName: 'September 2025',
        collaboratorsReportRun: mockReportRun,
        collaboratorsRevenueAdjustments: {
            totalCount: 15,
            currencyAgnosticTotalAmount: 255,
        },
        collaboratorsWhtAdjustments: {
            totalCount: 11,
            currencyAgnosticTotalAmount: 45,
        },
        collaboratorsPaymentApprovals: {
            nominalTotalAmount: 4500,
            totalCount: 8,
        },
    },
};

const noDpPaymentsMock: CollaboratorsDpPaymentsQuery = {
    dpPayments: {
        totalCount: 0,
        currencyAgnosticTotalAmount: 0,
        payments: [],
    },
};

const dpPaymentsMock: CollaboratorsDpPaymentsQuery = {
    dpPayments: {
        totalCount: 10,
        currencyAgnosticTotalAmount: 5000,
        payments: [
            {
                abacusStatementPeriodId: '',
                abacusStatementPeriodName: '',
                accountId: '',
                accountName: '',
                amount: 0,
                approvedDate: null,
                collaboratorId: '',
                collaboratorName: '',
                collaboratorTransactionId: null,
                createdDate: '',
                currency: '',
                id: '',
                payeeId: '',
                payoneerClientReferenceId: '',
                payoneerProgramId: 0,
                payoneerProgramName: '',
                agreementType: '',
                payoneerPaymentStatus: null,
            },
        ],
    },
};

const dpPaymentsApprovedMock: CollaboratorsDpPaymentsQuery = {
    dpPayments: {
        ...dpPaymentsMock.dpPayments,
        payments: [
            {
                ...dpPaymentsMock.dpPayments.payments[0],
                approvedDate: '2025-09-15T00:00:00Z',
            },
        ],
    },
};

const dpPaymentsSentMock: CollaboratorsDpPaymentsQuery = {
    dpPayments: {
        ...dpPaymentsApprovedMock.dpPayments,
        payments: [
            {
                ...dpPaymentsApprovedMock.dpPayments.payments[0],
                payoneerPaymentStatus: DpPayoneerPaymentStatus.INIT,
            },
        ],
    },
};

const pastPeriodNoWhtMock: CollaboratorsPeriodDetailQuery = {
    abacusStatementPeriod: {
        ...baseStatementPeriod,
        statementPeriodStatus: 'CLOSED',
        statementPeriodId: '321',
        statementPeriodName: 'September 2025',
        collaboratorsReportRun: mockReportRun,
        collaboratorsRevenueAdjustments: {
            totalCount: 15,
            currencyAgnosticTotalAmount: 255,
        },
        collaboratorsWhtAdjustments: {
            totalCount: 0,
            currencyAgnosticTotalAmount: 0,
        },
    },
};

describe('CollaboratorsPeriodDetail', () => {
    const startPollingMock = jest.fn();

    type PeriodDetailQueryResult = ReturnType<
        typeof periodDetailQueryModule.useCollaboratorsPeriodDetailQuery
    >;

    type DpPaymentsQueryResult = ReturnType<
        typeof dpPaymentsQueryModule.useCollaboratorsDpPaymentsQuery
    >;

    const asPeriodDetailQueryResult = (
        mock: Pick<
            PeriodDetailQueryResult,
            'data' | 'loading' | 'error' | 'startPolling'
        >
    ): PeriodDetailQueryResult => mock as unknown as PeriodDetailQueryResult;

    const asDpPaymentsQueryResult = (
        mock: Pick<DpPaymentsQueryResult, 'data' | 'loading' | 'error'>
    ): DpPaymentsQueryResult => mock as unknown as DpPaymentsQueryResult;

    beforeEach(() => {
        jest.clearAllMocks();

        jest.spyOn(
            periodDetailQueryModule,
            'useCollaboratorsPeriodDetailQuery'
        ).mockReturnValue(
            asPeriodDetailQueryResult({
                data: pastPeriodMock,
                loading: false,
                error: undefined,
                startPolling: startPollingMock,
            })
        );
    });

    const renderWithPeriodId = (
        id: string,
        features?: Record<string, boolean>
    ) =>
        renderInAppContext(
            <MemoryRouter initialEntries={[`/collaborators/period/${id}`]}>
                <Route path="/collaborators/period/:statementPeriodId">
                    <CollaboratorsPeriodDetail />
                </Route>
            </MemoryRouter>,
            features ? { identity: createIdentity({ features }) } : undefined
        );

    describe('When rendering current period', () => {
        beforeEach(() => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: currentPeriodWithRunMock,
                    loading: false,
                    error: undefined,
                    startPolling: startPollingMock,
                })
            );
        });

        it('renders loading state', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: undefined,
                    loading: true,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            const { getByTestId } = renderWithPeriodId('322');

            const loadingIndicator = getByTestId('LoadingPageIndicator');
            expect(loadingIndicator).toBeInTheDocument();
        });

        it('renders error state', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: undefined,
                    loading: false,
                    error: new ApolloError({ errorMessage: 'Test error' }),
                    startPolling: jest.fn(),
                })
            );

            const { getByText } = renderWithPeriodId('322');

            const errorMessage = getByText('Test error');
            expect(errorMessage).toBeInTheDocument();
        });

        it('renders period name as page title', () => {
            const { getByTestId } = renderWithPeriodId('322');

            const title = getByTestId('SuitePageHeader-title');
            expect(title).toHaveTextContent('October 2025');
        });

        it('"Start Calculation" button is enabled when current period has no report run', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: currentPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            const { getByTestId } = renderWithPeriodId('322');

            const button = getByTestId('start-calculation-button');
            expect(button).toBeEnabled();
        });

        it('Modal opens when "Start Calculation" button is clicked', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: currentPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            const { getByTestId, getByText } = renderWithPeriodId('322');

            const button = getByTestId('start-calculation-button');
            expect(button).toBeEnabled();
            fireEvent.click(button);

            const modalContent = getByText(
                'Are you sure you want to start the Collaborator calculation for October 2025?'
            );
            expect(modalContent).toBeInTheDocument();
        });

        it('Modal closes when canceling', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: currentPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            const { getByTestId, getByText, queryByText } =
                renderWithPeriodId('322');

            const button = getByTestId('start-calculation-button');
            fireEvent.click(button);

            const modalContent = getByText(
                'Are you sure you want to start the Collaborator calculation for October 2025?'
            );
            expect(modalContent).toBeInTheDocument();

            const cancelButton = getByText('Cancel');
            fireEvent.click(cancelButton);

            const closedModalContent = queryByText(
                'Start Collaborator Calculation for October 2025'
            );
            expect(closedModalContent).not.toBeInTheDocument();
        });

        it('Triggers calculation mutation when confirming in modal', async () => {
            const triggerMock = jest.fn().mockResolvedValue({
                data: {
                    triggerCollaboratorsAutoReportRun: {
                        __typename: 'CollaboratorReportRun',
                        id: '2',
                    },
                },
            });

            jest.spyOn(
                collaboratorMutations,
                'useTriggerCollaboratorAutoReportRun'
            ).mockReturnValue([
                triggerMock,
                {
                    data: undefined,
                    loading: false,
                    error: undefined,
                    called: false,
                    client: {} as any,
                    reset: jest.fn(),
                },
            ]);

            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: currentPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: startPollingMock,
                })
            );

            const { getByTestId, getByText, findByText } =
                renderWithPeriodId('322');

            const button = getByTestId('start-calculation-button');
            fireEvent.click(button);

            const confirmButton = getByText('Yes, Start Calculation');
            fireEvent.click(confirmButton);

            await waitFor(() => {
                expect(triggerMock).toHaveBeenCalledWith({
                    variables: { statementPeriodId: '322' },
                });
            });

            expect(startPollingMock).toHaveBeenCalled();

            const toast = await findByText('Calculation started');
            expect(toast).toBeInTheDocument();
        });

        it('Shows error toast when calculation mutation fails', async () => {
            const triggerMock = jest.fn().mockResolvedValue({
                data: {
                    triggerCollaboratorsAutoReportRun: {
                        __typename: 'Error',
                        message: 'Calculation failed',
                    },
                },
            });

            jest.spyOn(
                collaboratorMutations,
                'useTriggerCollaboratorAutoReportRun'
            ).mockReturnValue([
                triggerMock,
                {
                    data: undefined,
                    loading: false,
                    error: undefined,
                    called: false,
                    client: {} as any,
                    reset: jest.fn(),
                },
            ]);

            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: currentPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            const { getByTestId, getByText, findByText } =
                renderWithPeriodId('322');

            const button = getByTestId('start-calculation-button');
            fireEvent.click(button);

            const confirmButton = getByText('Yes, Start Calculation');
            fireEvent.click(confirmButton);

            await waitFor(() => {
                expect(triggerMock).toHaveBeenCalledWith({
                    variables: { statementPeriodId: '322' },
                });
            });

            expect(startPollingMock).not.toHaveBeenCalled();

            const toast = await findByText('Calculation failed');
            expect(toast).toBeInTheDocument();
        });

        it('"Start Calculation" button is disabled when current period has a report run', () => {
            const { getByTestId } = renderWithPeriodId('322');

            const button = getByTestId('start-calculation-button');
            expect(button).toBeDisabled();
        });
    });

    describe('When rendering past period', () => {
        beforeEach(() => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );
        });

        it('renders period name as page title', () => {
            const { getByTestId } = renderWithPeriodId('321');

            const title = getByTestId('SuitePageHeader-title');
            expect(title).toHaveTextContent('September 2025');
        });

        it('"Start Calculation" button is disabled', () => {
            const { getByTestId } = renderWithPeriodId('321');

            const button = getByTestId('start-calculation-button');
            expect(button).toBeDisabled();
        });

        it('Renders Revenue Allocations on Collaborator Ledgers', () => {
            const { getByText } = renderWithPeriodId('321');

            const allocationsLabel = getByText(
                'Revenue Allocations Added to Collaborator Ledgers'
            );
            expect(allocationsLabel).toBeInTheDocument();
            const allocationsContainer = allocationsLabel.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            expect(allocationsContainer).toBeInTheDocument();

            const {
                getByText: getByTextWithin,
                getByTestId: getByTestIdWithin,
            } = within(allocationsContainer);

            expect(getByTextWithin('1,234.00')).toBeInTheDocument();
            expect(getByTextWithin('250')).toBeInTheDocument();
            expect(
                getByTextWithin('Completed on May 02, 2025')
            ).toBeInTheDocument();

            const helpTooltipIcon = getByTestIdWithin('HelpTooltip');
            expect(helpTooltipIcon).toBeInTheDocument();
            fireEvent.mouseOver(helpTooltipIcon);
            const tooltip = getByText('Allocations incl. zero-report: 225');
            expect(tooltip).toBeInTheDocument();
        });

        it('renders Revenue Allocations on Client Ledger', () => {
            const { getByText } = renderWithPeriodId('321');

            const allocationsLabel = getByText(
                'Revenue Allocations on Client Ledger'
            );
            expect(allocationsLabel).toBeInTheDocument();
            const allocationsContainer = allocationsLabel.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            expect(allocationsContainer).toBeInTheDocument();

            const { getByText: getByTextWithin } = within(allocationsContainer);
            expect(getByTextWithin('255.00')).toBeInTheDocument();
            expect(getByTextWithin('15')).toBeInTheDocument();
        });

        it('renders WHT Allocations on Client Ledger', () => {
            const { getByText } = renderWithPeriodId('321');

            const allocationsLabel = getByText(
                'Collaborator WHT Allocations Adjustments have been applied to client ledger'
            );
            expect(allocationsLabel).toBeInTheDocument();
            const allocationsContainer = allocationsLabel.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            expect(allocationsContainer).toBeInTheDocument();

            const { getByText: getByTextWithin } = within(allocationsContainer);
            expect(getByTextWithin('45.00')).toBeInTheDocument();
            expect(getByTextWithin('11')).toBeInTheDocument();
        });

        it('renders Payments panel with dashes when no balances or approvals', () => {
            const { getByText } = renderWithPeriodId('321');

            const step1Label = getByText('Payment Approval Files');
            const step1Container = step1Label.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            expect(step1Container).toBeInTheDocument();
            expect(within(step1Container).getAllByText('--')).toHaveLength(2);

            const step2Label = getByText('Generate Payoneer Upload Files');
            const step2Container = step2Label.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            expect(step2Container).toBeInTheDocument();
            expect(within(step2Container).getAllByText('--')).toHaveLength(2);
        });

        it('renders Payments panel with data when DP payments exist', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodWithPaymentsMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            jest.spyOn(
                dpPaymentsQueryModule,
                'useCollaboratorsDpPaymentsQuery'
            ).mockReturnValue(
                asDpPaymentsQueryResult({
                    data: dpPaymentsApprovedMock,
                    loading: false,
                    error: undefined,
                })
            );

            const { getByText } = renderWithPeriodId('321');

            const step1Label = getByText('Payment Approval Files');
            const step1Container = step1Label.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            const { getByText: getByTextInStep1 } = within(step1Container);
            expect(getByTextInStep1('10')).toBeInTheDocument();
            expect(getByTextInStep1('5,000.00')).toBeInTheDocument();

            const step2Label = getByText('Generate Payoneer Upload Files');
            const step2Container = step2Label.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;
            const { getByText: getByTextInStep2 } = within(step2Container);
            expect(getByTextInStep2('8')).toBeInTheDocument();
            expect(getByTextInStep2('4,500.00')).toBeInTheDocument();
        });

        it('"Download" button is enabled when there are DP payments', () => {
            const { getByText } = renderWithPeriodId('321');

            expect(getByText('Download')).not.toBeDisabled();
        });

        it('"Download" button does not render when there are no DP payments', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodNoWhtMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            jest.spyOn(
                dpPaymentsQueryModule,
                'useCollaboratorsDpPaymentsQuery'
            ).mockReturnValue(
                asDpPaymentsQueryResult({
                    data: noDpPaymentsMock,
                    loading: false,
                    error: undefined,
                })
            );

            const { queryByText } = renderWithPeriodId('321');
            expect(queryByText('Download')).not.toBeInTheDocument();
        });

        it('renders Download button in "Generate Payoneer Upload Files" step when payment approvals exist', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodWithPaymentsMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            jest.spyOn(
                dpPaymentsQueryModule,
                'useCollaboratorsDpPaymentsQuery'
            ).mockReturnValue(
                asDpPaymentsQueryResult({
                    data: dpPaymentsMock,
                    loading: false,
                    error: undefined,
                })
            );

            const { getByText } = renderWithPeriodId('321');

            const stepLabel = getByText('Generate Payoneer Upload Files');
            const stepContainer = stepLabel.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;

            expect(
                within(stepContainer).getByText('Download')
            ).toBeInTheDocument();
        });

        it('does not render Download button in "Generate Payoneer Upload Files" step when no payment approvals', () => {
            const { getByText } = renderWithPeriodId('321');

            const stepLabel = getByText('Generate Payoneer Upload Files');
            const stepContainer = stepLabel.closest(
                '.Stepper-Step-content'
            ) as HTMLElement;

            expect(
                within(stepContainer).queryByText('Download')
            ).not.toBeInTheDocument();
        });

        it('calls replaceDpPayments mutation when Generate button is clicked', async () => {
            const pastPeriodWithWhtMock: CollaboratorsPeriodDetailQuery = {
                abacusStatementPeriod: {
                    ...pastPeriodMock.abacusStatementPeriod!,
                    collaboratorsWhtAllocationTransactions: {
                        __typename: 'CollaboratorTransactionResults' as const,
                        nominalTotalAmount: 100,
                        totalCount: 5,
                    },
                },
            };

            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodWithWhtMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            jest.spyOn(
                dpPaymentsQueryModule,
                'useCollaboratorsDpPaymentsQuery'
            ).mockReturnValue(
                asDpPaymentsQueryResult({
                    data: noDpPaymentsMock,
                    loading: false,
                    error: undefined,
                })
            );

            const replaceMock = jest.fn().mockResolvedValue({});
            jest.spyOn(
                replaceDpPaymentsMutationModule,
                'useReplaceDpPayments'
            ).mockReturnValue([
                replaceMock,
                {
                    data: undefined,
                    loading: false,
                    error: undefined,
                    called: false,
                    client: {} as any,
                    reset: jest.fn(),
                },
            ]);

            const { getByText } = renderWithPeriodId('321');

            fireEvent.click(getByText('Generate'));

            await waitFor(() => {
                expect(replaceMock).toHaveBeenCalled();
            });
        });
    });

    describe('When ABACUS_COLLABORATORS_PAYONEER_API_INTEGRATION is enabled', () => {
        const sendToPayoneerFF = {
            [USER_FEATURES.ABACUS_COLLABORATORS_PAYONEER_API_INTEGRATION]: true,
        };

        beforeEach(() => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodWithPaymentsMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            jest.spyOn(
                dpPaymentsQueryModule,
                'useCollaboratorsDpPaymentsQuery'
            ).mockReturnValue(
                asDpPaymentsQueryResult({
                    data: dpPaymentsApprovedMock,
                    loading: false,
                    error: undefined,
                })
            );
        });

        it('hides "Generate Payoneer Upload Files" step', () => {
            const { queryByText } = renderWithPeriodId('321', sendToPayoneerFF);

            expect(
                queryByText('Generate Payoneer Upload Files')
            ).not.toBeInTheDocument();
        });

        it('shows "Payments applied to Collaborator Ledger" step without "Apply" CTA', () => {
            const { queryByText, getByText } = renderWithPeriodId(
                '321',
                sendToPayoneerFF
            );

            expect(
                getByText('Payments applied to Collaborator Ledger')
            ).toBeInTheDocument();
            expect(
                queryByText('Apply Payments to Collaborator Ledgers')
            ).not.toBeInTheDocument();
            expect(queryByText('Apply')).not.toBeInTheDocument();
        });

        it('shows "Send Payments to Payoneer" step', () => {
            const { getByText } = renderWithPeriodId('321', sendToPayoneerFF);

            expect(getByText('Send Payments to Payoneer')).toBeInTheDocument();
        });

        it('"Send" button is enabled when there are approvals and payments have not been sent', () => {
            const { getByText } = renderWithPeriodId('321', sendToPayoneerFF);

            expect(getByText('Send')).not.toBeDisabled();
        });

        it('"Send" button is hidden when payments have already been sent', () => {
            jest.spyOn(
                dpPaymentsQueryModule,
                'useCollaboratorsDpPaymentsQuery'
            ).mockReturnValue(
                asDpPaymentsQueryResult({
                    data: dpPaymentsSentMock,
                    loading: false,
                    error: undefined,
                })
            );

            const { queryByText } = renderWithPeriodId('321', sendToPayoneerFF);

            expect(queryByText('Send')).not.toBeInTheDocument();
        });

        it('"Send" button is disabled when there are no payment approvals', () => {
            jest.spyOn(
                periodDetailQueryModule,
                'useCollaboratorsPeriodDetailQuery'
            ).mockReturnValue(
                asPeriodDetailQueryResult({
                    data: pastPeriodMock,
                    loading: false,
                    error: undefined,
                    startPolling: jest.fn(),
                })
            );

            const { getByText } = renderWithPeriodId('321', sendToPayoneerFF);

            expect(getByText('Send')).toBeDisabled();
        });

        it('opens confirmation modal when "Send" button is clicked', () => {
            const { getByText, getByTestId } = renderWithPeriodId(
                '321',
                sendToPayoneerFF
            );

            fireEvent.click(getByText('Send'));

            expect(
                getByText('Are you sure you want to send payments to Payoneer?')
            ).toBeInTheDocument();

            expect(getByTestId('send-payments-modal-content').textContent).toBe(
                'This will send 8 payments valued at 4,500.00 to Payoneer. Payments are across 1 Programs.These payments will be added to collaborator ledgers automatically.'
            );
        });

        it('calls submitDpPayments mutation, shows success toast, and closes modal when confirming', async () => {
            const submitMock = jest.fn().mockResolvedValue({
                data: { submitDpPayments: { submittedCount: 8 } },
            });

            jest.spyOn(
                submitDpPaymentsMutationModule,
                'useSubmitDpPayments'
            ).mockReturnValue([
                submitMock,
                {
                    data: undefined,
                    loading: false,
                    error: undefined,
                    called: false,
                    client: {} as any,
                    reset: jest.fn(),
                },
            ]);

            const { getByText, findByText, queryByText } = renderWithPeriodId(
                '321',
                sendToPayoneerFF
            );

            fireEvent.click(getByText('Send'));

            expect(
                getByText('Are you sure you want to send payments to Payoneer?')
            ).toBeInTheDocument();

            fireEvent.click(getByText('Yes, Send Payments'));

            await waitFor(() => {
                expect(submitMock).toHaveBeenCalled();
                expect(
                    queryByText(
                        'Are you sure you want to send payments to Payoneer?'
                    )
                ).not.toBeInTheDocument();
            });

            const toast = await findByText(
                'Payments were successfully sent to Payoneer.'
            );
            expect(toast).toBeInTheDocument();
        });
    });
});
