import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import { Route } from 'react-router-dom';
import * as abacusEventMutations from 'src/apollo/mutations/abacus-event';
import { ACCOUNTING_PERIOD_MECHANICALS_EVENT } from 'src/apollo/type-constants/accounting-period';
import {
    MechanicalDeductions,
    MechanicalDeductionsProps,
} from 'src/components/accounting-period/mechanical-deductions';
import { CONTRACT_TYPES, USER_FEATURES } from 'src/constants';
import { ABACUS_ACTION_STATUSES } from '@theorchard/accounting-apps-shared';

describe('<MechanicalDeductions>', () => {
    let defaultProps: MechanicalDeductionsProps;

    const render = (props: MechanicalDeductionsProps) =>
        renderInAppContext(<MechanicalDeductions {...props} />);

    const updatePeriodState = jest.fn();
    const setError = jest.fn();
    beforeEach(() => {
        defaultProps = {
            abacusStateId: '1',
            accountingPeriodId: 1,
            actionStatus: ABACUS_ACTION_STATUSES.INIT,
            contractType: CONTRACT_TYPES.DISTRIBUTION,
            isButtonDisabled: true,
            updatePeriodState,
            setError,
        };
    });
    describe('Prep Mech Deductions button for distribution accounting period', () => {
        it('renders disabled when sales are not delivered and exchange rates are not uploaded', () => {
            render(defaultProps);
            expect(screen.getByText('PREP MECH DEDUCTIONS')).toBeDefined();
            const btn = screen.getByTestId(
                'prepMechDeductionBtn'
            ) as HTMLButtonElement;
            expect(btn.disabled).toBeTruthy();
        });

        it('renders enabled when sales are delivered and exchange rates are uploaded', () => {
            defaultProps.isButtonDisabled = false;
            render(defaultProps);
            const btn = screen.getByTestId(
                'prepMechDeductionBtn'
            ) as HTMLButtonElement;
            expect(btn.disabled).toBeFalsy();
        });

        it('updates state when "PREP MECH DEDUCTIONS" button is clicked', () => {
            defaultProps.isButtonDisabled = false;
            render(defaultProps);
            const button = screen.getByText('PREP MECH DEDUCTIONS');
            fireEvent.click(button);
            expect(updatePeriodState).toHaveBeenCalled();
        });

        it('displays mech deductions text with refresh icon when mechanicals state is "running"', () => {
            defaultProps.actionStatus = ABACUS_ACTION_STATUSES.RUNNING;
            render(defaultProps);
            expect(screen.getByText('Preparing Mech Deductions')).toBeDefined();
            expect(screen.getByTestId('RefreshGlyphIcon')).toBeDefined();
            const btn = screen.getByTestId(
                'prepMechDeductionBtn'
            ) as HTMLButtonElement;
            expect(btn.disabled).toBeTruthy();
        });

        it('displays mech deductions text with checkmark icon when mechanicals state is "complete"', () => {
            defaultProps.actionStatus = ABACUS_ACTION_STATUSES.COMPLETE;
            render(defaultProps);
            expect(screen.getByText('Mech Deductions')).toBeDefined();
            expect(screen.getByTestId('CheckGlyphIcon')).toBeDefined();
            const btn = screen.getByTestId(
                'prepMechDeductionBtn'
            ) as HTMLButtonElement;
            expect(btn.disabled).toBeTruthy();
        });

        it('displays HelpIcon if mechanicals are not triggered and button is disabled', () => {
            defaultProps.isButtonDisabled = true;
            defaultProps.actionStatus = ABACUS_ACTION_STATUSES.INIT;
            render(defaultProps);
            expect(screen.getByTestId('mechDeductionsHelpIcon')).toBeDefined();
        });
    });

    describe('When the `abacus_contract_mechanical_deductions_calc` FF is on', () => {
        const render = () => {
            const accountingPeriodId = 1;
            const identity = {
                id: '123',
                features: {
                    [USER_FEATURES.ABACUS_CONTRACT_MECHANICAL_DEDUCTIONS_CALC]: true,
                },
            };

            renderInAppContext(
                <Route path="/accounting-period/:periodId">
                    <MechanicalDeductions {...defaultProps} />
                </Route>,
                {
                    pathname: `/accounting-period/${accountingPeriodId}`,
                    identity,
                }
            );
        };

        it('fires an abacus event when the "PREP MECH DEDUCTIONS" button is clicked', () => {
            const createAbacusEventMock = jest.fn().mockReturnValue({});
            const useCreateAbacusEventSpy = jest
                .spyOn(abacusEventMutations, 'useCreateAbacusEvent')
                .mockReturnValue(createAbacusEventMock);

            defaultProps.isButtonDisabled = false;
            defaultProps.actionStatus = ABACUS_ACTION_STATUSES.INIT;

            const accountingPeriodId = 1;

            render();

            const button = screen.getByText('PREP MECH DEDUCTIONS');
            fireEvent.click(button);

            expect(button).toBeDisabled();
            expect(useCreateAbacusEventSpy).toHaveBeenCalled();
            expect(createAbacusEventMock).toHaveBeenCalledWith({
                variables: {
                    eventName: ACCOUNTING_PERIOD_MECHANICALS_EVENT.EVENT_NAME,
                    targetType: ACCOUNTING_PERIOD_MECHANICALS_EVENT.TARGET_TYPE,
                    targetId: accountingPeriodId,
                },
            });
        });

        it('updates the state to "running" when the button is clicked', async () => {
            const createAbacusEventMock = jest.fn().mockResolvedValue({});
            const useCreateAbacusEventSpy = jest
                .spyOn(abacusEventMutations, 'useCreateAbacusEvent')
                .mockReturnValue(createAbacusEventMock);

            defaultProps.isButtonDisabled = false;
            defaultProps.actionStatus = ABACUS_ACTION_STATUSES.INIT;

            const accountingPeriodId = 1;
            render();

            const button = screen.getByText('PREP MECH DEDUCTIONS');
            fireEvent.click(button);
            expect(button).toBeDisabled();
            expect(useCreateAbacusEventSpy).toHaveBeenCalled();
            await waitFor(() => {
                expect(updatePeriodState).toHaveBeenCalledWith([
                    {
                        abacusStateId: defaultProps.abacusStateId,
                        actionStatus: ABACUS_ACTION_STATUSES.RUNNING,
                    },
                ]);
            });
            await waitFor(() => {
                expect(createAbacusEventMock).toHaveBeenCalledWith({
                    variables: {
                        eventName:
                            ACCOUNTING_PERIOD_MECHANICALS_EVENT.EVENT_NAME,
                        targetType:
                            ACCOUNTING_PERIOD_MECHANICALS_EVENT.TARGET_TYPE,
                        targetId: accountingPeriodId,
                    },
                });
            });
        });
    });

    describe('Prep Mech Deductions button for neighbouring_rights accounting period', () => {
        it('hides "PREP MECH DEDUCTIONS" link', () => {
            defaultProps = {
                contractType: CONTRACT_TYPES.NEIGHBOURING_RIGHTS,
                abacusStateId: '1',
                accountingPeriodId: 1,
                actionStatus: ABACUS_ACTION_STATUSES.INIT,
                isButtonDisabled: true,
                updatePeriodState,
                setError,
            };
            render(defaultProps);
            expect(screen.queryByText('PREP MECH DEDUCTIONS')).toBeNull();
        });
    });
});
