import React from 'react';
import { screen } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as accountDetailResponse from 'src/__fixtures__/graphql/account-detail-response.json';
import { useAccountPayeeBankDetailsQuery } from 'src/apollo/queries/account-payee-bank-details';
import { useCanPerformAction } from 'src/apollo/queries/can-perform';
import {
    NESTED_CLASS_NAME,
    PaymentDetailWhitelabel,
} from 'src/components/account-detail/payment-detail-whitelabel';
import {
    getLongDateFromDateTimeStamp,
    formatToMonthDayYear,
} from 'src/utils/date-helpers';

jest.mock('src/apollo/queries/can-perform', () => ({
    useCanPerformAction: jest.fn(),
}));

jest.mock('src/apollo/queries/account-payee-bank-details', () => ({
    useAccountPayeeBankDetailsQuery: jest.fn(),
}));

describe('PaymentDetailWhitelabel', () => {
    const render = (accountPayee: any) =>
        renderInAppContext(
            <PaymentDetailWhitelabel
                accountId="7"
                accountPayee={accountPayee}
            />
        );

    beforeEach(() => {
        jest.clearAllMocks();
        (useCanPerformAction as jest.Mock).mockReturnValue({ data: true });
        (useAccountPayeeBankDetailsQuery as jest.Mock).mockReturnValue({
            data: {
                abacusAccount: {
                    accountPayee: {
                        bankDetails: { modifiedAt: null },
                        actionStates: [],
                        accountPayeeKycNotification: { fileUploadLink: '' },
                    },
                },
            },
        });
    });

    it('review not started', () => {
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
            ],
        };

        render(accountPayee);

        expect(
            screen.getByText(
                'Bank details must be provided before this step can begin'
            )
        ).toBeDefined();
        expect(
            screen.getByText('Status of Payoneer checks will be displayed here')
        ).toBeDefined();
        expect(
            screen.getByText(
                'Once KYC process is completed you will be able to review banking details'
            )
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).toHaveClass('inactive');
        expect(steps[2]).toHaveClass('inactive');
    });

    it('review init', () => {
        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-11T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'init',
                    createdAt: createdAt,
                    lastModified: lastModified,
                },
            ],
        };

        const { baseElement } = render(accountPayee);

        expect(
            screen.getByText(
                `Received on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(
            screen.getByText("Payoneer's automated KYC checks are in progress.")
        ).toBeDefined();
        expect(
            screen.getByText(
                'Once KYC process is completed you will be able to review banking details'
            )
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).toHaveClass('inactive');

        expect(
            baseElement.querySelector(`.${NESTED_CLASS_NAME}`)
        ).toBeInTheDocument();
        expect(screen.getByText('Payment Data')).toBeInTheDocument();
        expect(screen.queryByText('Approval notes')).not.toBeInTheDocument();
    });

    it('review running when canEditBankInfo is true', () => {
        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-11T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'running',
                    createdAt: createdAt,
                    lastModified: lastModified,
                },
            ],
        };

        render(accountPayee);

        expect(
            screen.getByText(
                `Received on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                "Bank details did not automatically pass Payoneer's KYC checks"
            )
        ).toBeDefined();
        expect(screen.getByRole('link')).toHaveTextContent(
            'Upload documentation to Payoneer'
        );
        expect(screen.getByRole('link')).toHaveProperty(
            'href',
            accountPayee.accountPayeeKycNotification.fileUploadLink
        );
        expect(
            screen.getByText(
                'Once KYC process is completed you will be able to review banking details'
            )
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).toHaveClass('inactive');
    });

    it('review running when canEditBankInfo is false', () => {
        (useCanPerformAction as jest.Mock).mockReturnValue({ data: false });

        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-11T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'running',
                    createdAt: createdAt,
                    lastModified: lastModified,
                },
            ],
        };

        render(accountPayee);

        expect(
            screen.getByText(
                `Received on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                "Bank details did not automatically pass Payoneer's KYC checks"
            )
        ).toBeDefined();
        expect(
            screen.queryByText('Upload documentation to Payoneer')
        ).toBeNull();
        expect(
            screen.queryByText(
                'Please follow the link to confirm next steps and to upload any',
                { exact: false }
            )
        ).toBeNull();
        expect(
            screen.getByText(
                'Once KYC process is completed you will be able to review banking details'
            )
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).toHaveClass('inactive');
    });

    it('review running takes precedence when payment_eligibility is approved', () => {
        // When banking_details_review is "running", buildReviewRunningSteps should be used
        // regardless of payment_eligibility status (even if it is "approved").
        // This covers the early-return guard in getStepsStrategy.
        const lastModified = '2023-02-11T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    __typename: 'AbacusState',
                    abacusStateId: '665984',
                    actionName: 'payment_eligibility',
                    actionStatus: 'approved',
                },
                {
                    __typename: 'AbacusState',
                    abacusStateId: '665985',
                    actionName: 'banking_details_review',
                    actionStatus: 'running',
                    message: 'KYC APPROVED',
                    lastModified,
                },
            ],
        };

        render(accountPayee);

        // Should render buildReviewRunningSteps, NOT PaymentDetailApproved
        expect(
            screen.queryByTestId('PaymentDetailApproved')
        ).not.toBeInTheDocument();

        expect(
            screen.getByText(
                `Received on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                "Bank details did not automatically pass Payoneer's KYC checks"
            )
        ).toBeDefined();
        expect(screen.getByRole('link')).toHaveTextContent(
            'Upload documentation to Payoneer'
        );
        expect(
            screen.getByText(
                'Once KYC process is completed you will be able to review banking details'
            )
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).toHaveClass('inactive');
    });

    it('review approved', () => {
        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-11T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'approved',
                    createdAt: createdAt,
                    lastModified: lastModified,
                },
            ],
        };

        const { baseElement } = render(accountPayee);

        expect(
            screen.getByText(
                `Received on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(
            screen.getByText('Bank details have passed KYC checks')
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).not.toHaveClass('inactive');

        expect(
            baseElement.querySelector(`.${NESTED_CLASS_NAME}`)
        ).toBeInTheDocument();
        expect(screen.getByText('Payment Data')).toBeInTheDocument();
        expect(screen.queryByText('Approval notes')).not.toBeInTheDocument();
    });

    it('review rejected', () => {
        const message = 'test reason';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'rejected',
                    message,
                },
            ],
        };

        const { baseElement } = render(accountPayee);

        expect(
            screen.getByText(
                'Please instruct the client to re-submit their bank details in the Banking & Tax app.'
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                "Bank details did not automatically pass Payoneer's KYC checks"
            )
        ).toBeDefined();
        expect(
            screen.getByText(`KYC check failed because of ${message}`)
        ).toBeDefined();
        expect(
            screen.getByText(
                'Once KYC process is completed you will be able to review banking details'
            )
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).toHaveClass('inactive');

        expect(
            baseElement.querySelector(`.${NESTED_CLASS_NAME}`)
        ).toBeInTheDocument();
        expect(screen.getByText('Payment Data')).toBeInTheDocument();
        expect(screen.queryByText('Approval notes')).not.toBeInTheDocument();
    });

    it('review approved eligibility running', () => {
        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-11T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'running',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'approved',
                    createdAt: createdAt,
                    lastModified: lastModified,
                },
            ],
        };

        const { baseElement } = render(accountPayee);

        expect(
            screen.getByText(
                `Received on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(
            screen.getByText('Bank details have passed KYC checks')
        ).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).not.toHaveClass('inactive');
        expect(steps[2]).not.toHaveClass('inactive');

        expect(
            baseElement.querySelector(`.${NESTED_CLASS_NAME}`)
        ).toBeInTheDocument();
        expect(screen.getByText('Payment Data')).toBeInTheDocument();
        expect(screen.queryByText('Approval notes')).not.toBeInTheDocument();
    });

    it('review rejected with notes', () => {
        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-12T16:40:26.000000';
        const testNotes = 'test notes';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'rejected',
                    createdAt: createdAt,
                    lastModified: lastModified,
                    message: testNotes,
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'approved',
                },
            ],
        };

        const { baseElement } = render(accountPayee);

        expect(
            screen.getByText(
                'Bank details must be provided before this step can begin'
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                'Please instruct the client to enter their bank details in the Banking & Tax app.'
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                'To get Payoneer to complete the checks you need the banking details'
            )
        ).toBeDefined();

        expect(
            screen.getByText(
                `Rejected on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(screen.getByText('SEE NOTES')).toBeDefined();
        expect(screen.getByText(testNotes)).toBeDefined();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).toHaveClass('inactive');
        expect(steps[2]).not.toHaveClass('inactive');

        expect(
            baseElement.querySelector(`.${NESTED_CLASS_NAME}`)
        ).toBeInTheDocument();
        expect(screen.getByText('Payment Data')).toBeInTheDocument();
        expect(screen.queryByText('Approval notes')).not.toBeInTheDocument();
    });

    it('review rejected without notes', () => {
        const createdAt = '2023-02-10T16:40:26.000000';
        const lastModified = '2023-02-12T16:40:26.000000';
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'rejected',
                    createdAt: createdAt,
                    lastModified: lastModified,
                    message: null,
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'approved',
                },
            ],
        };

        render(accountPayee);

        expect(
            screen.getByText(
                'Bank details must be provided before this step can begin'
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                'Please instruct the client to enter their bank details in the Banking & Tax app.'
            )
        ).toBeDefined();
        expect(
            screen.getByText(
                'To get Payoneer to complete the checks you need the banking details'
            )
        ).toBeDefined();

        expect(
            screen.getByText(
                `Rejected on ${getLongDateFromDateTimeStamp(lastModified)}`
            )
        ).toBeDefined();
        expect(screen.queryByText('SEE NOTES')).toBeNull();

        const steps = screen.queryAllByTestId('Stepper-Step');
        expect(steps[0]).not.toHaveClass('inactive');
        expect(steps[1]).toHaveClass('inactive');
        expect(steps[2]).not.toHaveClass('inactive');
    });

    it('renders <PaymentDetailApproved/> when eligibility and bank_details are approved', () => {
        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'approved',
                    createdAt: '2023-02-10T16:40:26.000000',
                    message: null,
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'approved',
                    createdAt: '2023-02-11T16:40:26.000000',
                    message: 'KYC APPROVED',
                },
            ],
        };

        (useAccountPayeeBankDetailsQuery as jest.Mock).mockReturnValue({
            data: {
                abacusAccount: {
                    accountPayee,
                },
            },
        });

        const { baseElement } = render(accountPayee);

        expect(screen.getByTestId('PaymentDetailApproved')).toBeDefined();
        expect(screen.getByText('Approval notes')).toBeInTheDocument();
        expect(
            baseElement.querySelector(`.${NESTED_CLASS_NAME}`)
        ).not.toBeInTheDocument();
        expect(screen.queryByText('Payment Data')).not.toBeInTheDocument();
    });

    it('renders Reject button when banking details review is running and canEditBankInfo is true', () => {
        (useCanPerformAction as jest.Mock).mockReturnValue({ data: true });

        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'running',
                },
            ],
        };

        render(accountPayee);

        expect(
            screen.getByRole('button', { name: /reject/i })
        ).toBeInTheDocument();
    });

    it('does not render Reject button when canEditBankInfo is false', () => {
        (useCanPerformAction as jest.Mock).mockReturnValue({ data: false });

        const accountPayee = {
            ...accountDetailResponse.abacusAccount.accountPayee,
            actionStates: [
                {
                    actionName: 'payment_eligibility',
                    actionStatus: 'init',
                },
                {
                    actionName: 'banking_details_review',
                    actionStatus: 'running',
                },
            ],
        };
        render(accountPayee);

        expect(
            screen.queryByRole('button', { name: /reject/i })
        ).not.toBeInTheDocument();
    });

    describe('PaymentDetailWhitelabel - renderLastEditDateLabel', () => {
        it('renders last edit date when modifiedAt is defined', () => {
            const modifiedAt = '2025-08-18T12:00:00.000Z';

            (useAccountPayeeBankDetailsQuery as jest.Mock).mockReturnValue({
                data: {
                    abacusAccount: {
                        accountPayee: {
                            bankDetails: { modifiedAt },
                        },
                    },
                },
            });

            render(accountDetailResponse.abacusAccount.accountPayee);

            const formattedDate = `Last Edit Date: ${formatToMonthDayYear(modifiedAt)}`;
            expect(screen.getByText(formattedDate)).toBeInTheDocument();
        });

        it('renders nothing when modifiedAt is undefined', () => {
            (useAccountPayeeBankDetailsQuery as jest.Mock).mockReturnValue({
                data: {
                    abacusAccount: {
                        accountPayee: {
                            bankDetails: { modifiedAt: undefined },
                        },
                    },
                },
            });

            render(accountDetailResponse.abacusAccount.accountPayee);

            const lastEditElement = document.querySelector('.last-edit-date');
            expect(lastEditElement).not.toBeInTheDocument();
            expect(lastEditElement?.textContent).toBe(undefined);
        });
    });
});
