import React from 'react';
import { screen, within } from '@testing-library/react';
import { type Identity } from '@theorchard/suite-frontend';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as accountResponse from 'src/__fixtures__/graphql/account-detail-response.json';
import { PaymentType } from 'src/apollo/definitions/globalTypes';
import PaymentGeneralDetail, {
    type PaymentGeneralDetailProps,
} from 'src/components/account-detail/payment-general-detail';
import { PAYMENT_SCHEDULE_MAP } from 'src/constants';
import { smartFormatter } from 'src/utils/amount-helpers';
import { getCurrencyLabel } from 'src/utils/currency';

describe('<PaymentGeneralDetail>', () => {
    const { accountPaymentTerm, accountPayee } = accountResponse.abacusAccount;
    const defaultProps: PaymentGeneralDetailProps = {
        // @ts-expect-error: fixture type doesn't exactly match
        paymentGeneralDetails: {
            accountPayeeId: '5555555',
            ...accountPaymentTerm,
            payoneerProgramId: accountPayee.payoneerProgramId,
            // TODO: add this to the fixture once the payoneerProgram field
            // has replaced payoneerProgramId across the frontend.
            // See https://github.com/theorchard/graphql-abacus/pull/450
            payoneerProgramName: 'GDA Test',
            paymentDescription: 'Test payment description',
        },
    };

    const render = (
        props: PaymentGeneralDetailProps,
        identity: Identity = {
            profileType: 'AbacusProfile',
            features: [] as any,
            id: '',
        }
    ) =>
        renderInAppContext(<PaymentGeneralDetail {...props} />, {
            identity,
        });

    it('renders', () => {
        render(defaultProps);
        expect(screen.getByTestId('paymentGeneralDetails')).toBeDefined();
    });

    it('displays payment entity', () => {
        render(defaultProps);
        expect(screen.getByText('Paid By')).toBeDefined();
        expect(
            screen.getByText(
                accountPaymentTerm.paymentEntity?.paymentEntityName
            )
        ).toBeDefined();
    });

    it('displays default fallback value with no payment entity', () => {
        render({
            paymentGeneralDetails: {
                ...defaultProps.paymentGeneralDetails,
                paymentEntity: null,
            },
        });
        const container = screen.getByTestId('paidBy');
        expect(within(container).getByText('-')).toBeDefined();
    });

    it('displays agreement type', () => {
        render(defaultProps);
        expect(screen.getByText('Agreement Type')).toBeDefined();
        expect(
            screen.getByText(accountPaymentTerm.agreementType.agreementType)
        ).toBeDefined();
    });

    it('displays default fallback value with no agreement type', () => {
        render({
            paymentGeneralDetails: {
                ...defaultProps.paymentGeneralDetails,
                agreementType: null,
            },
        });
        const container = screen.getByTestId('agreementType');
        expect(within(container).getByText('-')).toBeDefined();
    });

    it('displays payment currency', () => {
        render(defaultProps);
        const currency =
            getCurrencyLabel(accountPaymentTerm.currencyCode) ?? '';
        expect(screen.getByText('Payment Currency')).toBeDefined();
        expect(screen.getByText(currency)).toBeDefined();
    });

    it('displays payoneer program name', () => {
        render({
            paymentGeneralDetails: {
                ...defaultProps.paymentGeneralDetails,
                paymentType: PaymentType.PAYONEER,
            },
        });
        expect(screen.getByText('Payoneer Program')).toBeDefined();
        expect(
            screen.getByText(
                defaultProps.paymentGeneralDetails.payoneerProgramName as string
            )
        ).toBeDefined();
    });

    it('displays Payee ID', () => {
        render(defaultProps);
        expect(screen.getByText('Payee ID')).toBeDefined();
        expect(screen.getByText('5555555')).toBeDefined();
    });

    it('displays Payment Description', () => {
        render(defaultProps);
        expect(screen.getByText('Payment Description')).toBeDefined();
        expect(
            screen.getByText(
                defaultProps.paymentGeneralDetails.paymentDescription as string
            )
        ).toBeDefined();
    });

    it('displays payment schedule', () => {
        render(defaultProps);
        expect(screen.getByText('Payment Schedule')).toBeDefined();
        expect(
            screen.getByText(
                PAYMENT_SCHEDULE_MAP[accountPaymentTerm.paymentSchedule]
            )
        ).toBeDefined();
    });

    it('displays payment minimum', () => {
        render(defaultProps);
        const { currencyCode, paymentMinimum } = accountPaymentTerm;
        const currencyName = getCurrencyLabel(accountPaymentTerm.currencyCode);
        const paymentMin = `${smartFormatter(
            paymentMinimum,
            currencyCode
        )} ${currencyName}`;

        expect(screen.getByText('Payment Minimum')).toBeDefined();
        expect(screen.getByText(paymentMin)).toBeDefined();
    });

    it('renders an edit button', () => {
        render(defaultProps);
        const editButton = screen.getByTestId('account-detail-edit-btn');
        expect(editButton.classList.contains('btn')).toBe(true);
    });

    it('does not render an edit button for non AbacusProfile', () => {
        render(defaultProps, {
            profileType: 'OtherProfile',
            features: [] as any,
            id: '',
        });
        const editButton = screen.queryByText('Edit');

        expect(editButton).toBeNull();
    });

    describe('with paymentType PAYONEER', () => {
        it('displays payoneer program ID', () => {
            render({
                paymentGeneralDetails: {
                    ...defaultProps.paymentGeneralDetails,
                    paymentType: PaymentType.PAYONEER,
                },
            });
            expect(screen.getByText('Payoneer Program ID')).toBeDefined();
            expect(
                screen.getByText(accountPayee.payoneerProgramId)
            ).toBeDefined();
        });
        it('hide SAP Vendor ID', () => {
            render({
                paymentGeneralDetails: {
                    ...defaultProps.paymentGeneralDetails,
                    paymentType: PaymentType.PAYONEER,
                },
            });
            expect(screen.queryByText('SAP Vendor ID')).toBeFalsy();
            expect(screen.queryByText(accountPayee.sapVendorId)).toBeFalsy();
        });
    });

    describe('with paymentType SAP', () => {
        it('displays SAP Vendor ID', () => {
            render({
                paymentGeneralDetails: {
                    ...defaultProps.paymentGeneralDetails,
                    paymentType: PaymentType.SAP,
                    sapVendorId: accountPayee.sapVendorId,
                },
            });
            expect(screen.getByText('SAP Vendor ID')).toBeDefined();
            expect(screen.getByText(accountPayee.sapVendorId)).toBeDefined();
        });
        it('shows payoneer program', () => {
            render({
                paymentGeneralDetails: {
                    ...defaultProps.paymentGeneralDetails,
                    paymentType: PaymentType.SAP,
                },
            });
            expect(screen.getByText('Payoneer Program ID')).toBeDefined();
            expect(
                screen.getByText(accountPayee.payoneerProgramId)
            ).toBeDefined();

            expect(screen.getByText('Payoneer Program')).toBeDefined();
            expect(
                screen.getByText(
                    defaultProps.paymentGeneralDetails
                        .payoneerProgramName as string
                )
            ).toBeDefined();
        });
    });
});
