import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { type Identity } from '@theorchard/suite-frontend';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as accountDetail from 'src/__fixtures__/graphql/account-detail-response.json';
import * as accountQuery from 'src/apollo/queries/account';
import PaymentGroupTooltip, {
    type PaymentGroupTooltipProps,
} from 'src/components/payment-group-detail/payment-group-tooltip';
import { PAYMENT_SCHEDULE_MAP } from 'src/constants';
import { getCurrencyLabel } from 'src/utils/currency';

describe('<PaymentGroupTooltip />', () => {
    const { createRange } = window.document;
    const { accountId, accountName } = accountDetail.abacusAccount;
    const nonReusablePaymentDetail = {
        groupCriteria: { accountId },
        groupName: accountName,
        isReusable: false,
        paymentGroupId: '2',
    };
    const reusablePaymentDetail = {
        groupCriteria: {
            currencyCodes: ['AUD', 'EUR', 'JPY', 'NOK', 'SEK'],
            referencePaymentEntities: [
                {
                    referencePaymentEntityId: '1',
                    paymentEntityName: 'AWA-UK',
                },
            ],
            paymentSchedules: [
                '45_days_after_month_end',
                '60_days_after_month_end',
            ],
            accountId: null,
            accountIds: null,
        },
        groupName: 'Orange Peal Records, Inc.',
        isReusable: true,
        paymentGroupId: '3',
    };
    let useAccountSpy: jest.SpyInstance;

    const render = (props: PaymentGroupTooltipProps, identity?: Identity) =>
        renderInAppContext(<PaymentGroupTooltip {...props} />, { identity });

    afterAll(() => (window.document.createRange = createRange));
    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        useAccountSpy = jest
            .spyOn(accountQuery, 'useAccountFullDetail')
            .mockReturnValue({
                // @ts-expect-error: fixture type doesn't exactly match
                data: accountDetail,
            });
    });

    it('renders for reusable payment group', () => {
        const props: PaymentGroupTooltipProps = {
            paymentGroupDetails: reusablePaymentDetail,
            accountId: null,
            accountIds: null,
        };
        const { container } = render(props);
        expect(container).toBeDefined();
    });

    it('renders for non-reusable payment group', () => {
        const props: PaymentGroupTooltipProps = {
            // @ts-expect-error: mock data type doesn't exactly match
            paymentGroupDetails: nonReusablePaymentDetail,
            accountId,
        };
        const { container } = render(props);
        expect(container).toBeDefined();
    });

    it('displays group criteria when tooltip is clicked', async () => {
        if (window.document)
            window.document.createRange = () => ({
                setStart: () => {},
                setEnd: () => {},
                // @ts-expect-error: ignore missing properties
                commonAncestorContainer: {
                    nodeName: 'BODY',
                    ownerDocument: document,
                },
            });
        const props: PaymentGroupTooltipProps = {
            paymentGroupDetails: reusablePaymentDetail,
            accountId: null,
            accountIds: null,
        };
        render(props);
        const helpIcon = screen.getByTestId('HelpTooltip');

        fireEvent.mouseOver(helpIcon);

        const { currencyCodes, referencePaymentEntities, paymentSchedules } =
            reusablePaymentDetail.groupCriteria;

        const currencies = currencyCodes
            .map(code => getCurrencyLabel(code))
            .join(', ');
        const entity = referencePaymentEntities[0].paymentEntityName;
        const schedules = paymentSchedules
            .map(paymentSchedule => PAYMENT_SCHEDULE_MAP[paymentSchedule])
            .join(', ');

        expect(await screen.findByTestId('HelpTooltip')).toBeDefined();
        expect(screen.getByText('Payment Currency')).toBeDefined();
        expect(screen.getByText(currencies)).toBeDefined();

        expect(screen.getByText('Paid By')).toBeDefined();
        expect(screen.getByText(entity)).toBeDefined();

        expect(screen.getByText('Payment Schedule')).toBeDefined();
        expect(screen.getByText(schedules)).toBeDefined();
    });

    it('requests account detail when accountId is provided', () => {
        const props: PaymentGroupTooltipProps = {
            // @ts-expect-error: mock data type doesn't exactly match
            paymentGroupDetails: nonReusablePaymentDetail,
            accountId,
        };
        render(props);
        expect(useAccountSpy).toHaveBeenCalledWith(parseInt(accountId, 10));

        const helpIcon = screen.getByTestId('HelpTooltip');
        fireEvent.mouseOver(helpIcon);

        expect(screen.getByText('Payment Currency')).toBeDefined();
        expect(screen.getByText('USD (US Dollar)')).toBeDefined();

        expect(screen.getByText('Paid By')).toBeDefined();
        expect(screen.getByText('AWAL-UK')).toBeDefined();

        expect(screen.getByText('Payment Schedule')).toBeDefined();
        expect(screen.getByText('30 days after quarter end')).toBeDefined();
    });

    describe('account selection', () => {
        const identity = {
            features: {},
            id: '',
        };

        it(`uses 'accountId' if there is no 'accountIds'`, () => {
            const props: PaymentGroupTooltipProps = {
                // @ts-expect-error: mock data type doesn't exactly match
                paymentGroupDetails: nonReusablePaymentDetail,
                accountId: '9999',
            };
            render(props, identity);

            expect(useAccountSpy).toHaveBeenCalledWith(
                parseInt(props.accountId ?? '0', 10)
            );
            expect(screen.getByTestId('InfoGlyphIcon')).toBeInTheDocument();
        });

        it(`uses 'accountIds' prop and <Tooltip> shouldn't be presented`, () => {
            const props: PaymentGroupTooltipProps = {
                // @ts-expect-error: mock data type doesn't exactly match
                paymentGroupDetails: nonReusablePaymentDetail,
                accountId: '9999',
                accountIds: ['8888', '7777'],
            };

            render(props, identity);

            expect(useAccountSpy).not.toHaveBeenCalled();
            expect(
                screen.queryByTestId('InfoGlyphIcon')
            ).not.toBeInTheDocument();
        });

        it('renders tooltip when there is only one account in accountIds', () => {
            const props: PaymentGroupTooltipProps = {
                // @ts-expect-error: mock data type doesn't exactly match
                paymentGroupDetails: nonReusablePaymentDetail,
                accountIds: ['8888'],
            };

            render(props, identity);

            expect(useAccountSpy).toHaveBeenCalledWith(8888);
            expect(screen.getByTestId('InfoGlyphIcon')).toBeInTheDocument();
        });
    });
});
