import React from 'react';
import { fireEvent, screen, within } from '@testing-library/react';
import { renderInAppContext, createIdentity } from '@theorchard/suite-testing';
import * as statementPeriodResponse from 'src/__fixtures__/graphql/statement-period-response.json';
import * as statementPeriodMutations from 'src/apollo/mutations/statement-periods';
import * as moneyhubDbtRefreshMutation from 'src/apollo/mutations/moneyhubDbtRefresh';
import ShowCustomerAccounting, {
    ShowCustomerAccountingPropTypes,
} from 'src/components/statement-period-detail/show-customer-accounting';
import { STATEMENT_PERIOD_STATUSES } from 'src/constants';
import {
    TERM_LIVE_IN_ACCOUNTING,
    TERM_SHOW_IN_ACCOUNTING,
} from '../show-in-customer-accounting-button';

describe('<ShowCustomerAccounting>', () => {
    let useUpdateStatementPeriodPaymentEntitySpy: any;
    let useMoneyhubDbtRefreshSpy: any;
    const defaultProps = {
        statementPeriod:
            statementPeriodResponse.abacusStatementPeriod as ShowCustomerAccountingPropTypes['statementPeriod'],
    };

    const updatePaymentEntity = jest.fn().mockResolvedValue({});
    const useMoneyhubDbtRefresh = jest.fn().mockResolvedValue({});

    beforeEach(() => {
        useUpdateStatementPeriodPaymentEntitySpy = jest
            .spyOn(
                statementPeriodMutations,
                'useUpdateStatementPeriodPaymentEntity'
            )
            .mockReturnValue(updatePaymentEntity);
        useMoneyhubDbtRefreshSpy = jest
            .spyOn(moneyhubDbtRefreshMutation, 'useMoneyhubDbtRefresh')
            .mockReturnValue(useMoneyhubDbtRefresh);
    });

    const render = (props: ShowCustomerAccountingPropTypes, identity: any) =>
        renderInAppContext(<ShowCustomerAccounting {...props} />, { identity });

    const mockIdentity = createIdentity({
        features: {},
    });
    it('renders', () => {
        render(defaultProps, mockIdentity);

        const checkmarkIcon = screen.queryByTestId('CompleteIconTestid');
        expect(checkmarkIcon).toBeNull();
        expect(useUpdateStatementPeriodPaymentEntitySpy).toHaveBeenCalled();
        expect(useMoneyhubDbtRefreshSpy).toHaveBeenCalled();
    });

    it('renders a list of payment entities', () => {
        render(defaultProps, mockIdentity);

        defaultProps?.statementPeriod?.paymentEntities.forEach(
            ({ referencePaymentEntity }) => {
                const paymentEntityItem = screen.getByTestId(
                    `payment-entity-${referencePaymentEntity.referencePaymentEntityId}`
                );

                if (!referencePaymentEntity.paymentEntityName)
                    throw new Error('no payment entity name');

                expect(
                    within(paymentEntityItem).getByText(
                        referencePaymentEntity.paymentEntityName
                    )
                ).toBeInTheDocument();
            }
        );
    });

    it('renders action buttons and statuses', () => {
        render(defaultProps, mockIdentity);

        const showButtons = screen.getAllByRole('button', {
            name: TERM_SHOW_IN_ACCOUNTING,
        });
        expect(Object.keys(showButtons).length).toEqual(2);

        const liveStatuses = screen.getAllByText(TERM_LIVE_IN_ACCOUNTING);
        expect(Object.keys(liveStatuses).length).toEqual(1);
    });

    it('renders a popup after clicking an action link', () => {
        render(defaultProps, mockIdentity);

        const showButton = screen.getAllByRole('button', {
            name: TERM_SHOW_IN_ACCOUNTING,
        })[0];
        expect(showButton).toBeDefined();

        fireEvent.click(showButton);
        const modalContent = screen.getByTestId(
            'ShowCustomerAccountingModalTestid'
        );
        expect(modalContent).toBeDefined();
    });

    it('updates payment entity after clicking the modal button', () => {
        render(defaultProps, mockIdentity);

        const showButton = screen.getAllByRole('button', {
            name: TERM_SHOW_IN_ACCOUNTING,
        })[0];
        expect(showButton).toBeDefined();

        fireEvent.click(showButton);
        const button = screen.getByText('Yes, Show');

        fireEvent.click(button);
        expect(updatePaymentEntity).toHaveBeenCalled();
    });

    it('triggers dbt refresh after clicking the modal button', () => {
        render(defaultProps, mockIdentity);

        const showButton = screen.getAllByRole('button', {
            name: TERM_SHOW_IN_ACCOUNTING,
        })[0];
        expect(showButton).toBeDefined();

        fireEvent.click(showButton);
        const button = screen.getByText('Yes, Show');

        fireEvent.click(button);
        expect(useMoneyhubDbtRefresh).toHaveBeenCalled();
    });

    it('renders action buttons when statement period is closed', () => {
        render(
            {
                ...defaultProps,
                statementPeriod: {
                    ...defaultProps.statementPeriod,
                    statementPeriodStatus: STATEMENT_PERIOD_STATUSES.CLOSED,
                } as ShowCustomerAccountingPropTypes['statementPeriod'],
            },
            mockIdentity
        );

        const showButtons = screen.getAllByRole('button', {
            name: TERM_SHOW_IN_ACCOUNTING,
        });

        showButtons.forEach((button: any) =>
            expect(button).toHaveProperty('disabled', true)
        );
    });

    it('does NOT render checkmark icon when all customer accounting actions are completed', () => {
        render(defaultProps, mockIdentity);
        const checkmarkIcon = screen.queryByTestId('CompleteIconTestid');

        expect(checkmarkIcon).toBeFalsy();
    });

    it('renders redesign-specific container', () => {
        const { container } = render(defaultProps, mockIdentity);
        expect(
            container.getElementsByClassName('ShowCustomerAccounting-Redesign')
                .length
        ).toBe(1);
        expect(screen.getByText('Paid By Status & Action')).toBeDefined();
    });
});
