import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import * as abacusEventMutations from 'src/apollo/mutations/abacus-event';
import {
    ClosePeriodModal,
    ClosePeriodModalPropTypes,
} from 'src/components/accounting-period/close-period-modal';
import { ABACUS_ACTION_STATUSES } from '@theorchard/accounting-apps-shared';

describe('<ClosePeriodModal/>', () => {
    const accountingPeriodId: number = 123;
    const defaultProps: ClosePeriodModalPropTypes = {
        accountingPeriodId,
        actionStatus: ABACUS_ACTION_STATUSES.INIT,
        closeState: {
            abacusStateId: '1',
            actionStatus: ABACUS_ACTION_STATUSES.INIT,
            actionName: 'CLOSE_PERIOD',
            message: null,
        },
        isButtonDisabled: false,
        updatePeriodState: jest.fn(),
        setError: jest.fn(),
    };

    const render = (props: ClosePeriodModalPropTypes = defaultProps) =>
        renderInAppContext(<ClosePeriodModal {...props} />);

    const createAbacusEvent = jest.fn().mockResolvedValue({});
    let createAbacusEventSpy: jest.SpyInstance;

    afterEach(jest.restoreAllMocks);

    beforeEach(() => {
        createAbacusEventSpy = jest
            .spyOn(abacusEventMutations, 'useCreateAbacusEvent')
            .mockReturnValue(createAbacusEvent);
    });

    it('renders', () => {
        render();

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');

        expect(closePeriodBtn).toBeInTheDocument();
        expect(createAbacusEventSpy).toHaveBeenCalled();
    });

    it('renders with "Close Period" button disabled when specified', () => {
        const props = {
            ...defaultProps,
            isButtonDisabled: true,
        };

        render(props);

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');

        expect(closePeriodBtn).toBeInTheDocument();
        expect(closePeriodBtn).toBeDisabled();
    });

    it('opens when "Close Period" button is clicked', () => {
        render();

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');
        fireEvent.click(closePeriodBtn);

        const modalContent = screen.getByTestId('close-period-modal-content');
        const confirmBtn = screen.getByRole('button', {
            name: 'Yes, Close This Period',
        });

        expect(modalContent).toBeInTheDocument();
        expect(confirmBtn).toBeInTheDocument();
    });

    it('disables the confirm button when clicked', async () => {
        render();

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');
        fireEvent.click(closePeriodBtn);

        const confirmBtn = screen.getByRole('button', {
            name: 'Yes, Close This Period',
        });
        fireEvent.click(confirmBtn);

        expect(confirmBtn).toBeDisabled();
    });

    it('displays the action status icon for "running" when the state is running', () => {
        const props = {
            ...defaultProps,
            closeState: {
                ...defaultProps.closeState,
                actionStatus: ABACUS_ACTION_STATUSES.RUNNING,
            },
        };

        render(props);

        const actionStatusIcon = screen.getByTestId('ActionStatusIcon-init');
        expect(actionStatusIcon).toBeInTheDocument();
    });

    it('displays the action status icon for "complete" when the state is complete', () => {
        const props = {
            ...defaultProps,
            closeState: {
                ...defaultProps.closeState,
                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
            },
        };
        render(props);

        const actionStatusIcon = screen.getByTestId('ActionStatusIcon-init');
        expect(actionStatusIcon).toBeInTheDocument();
    });

    it('updates the accounting period status when confirm button is clicked', async () => {
        render();
        const closePeriodBtn = screen.getByTestId('closePeriodBtn');
        fireEvent.click(closePeriodBtn);
        const confirmBtn = screen.getByRole('button', {
            name: 'Yes, Close This Period',
        });
        fireEvent.click(confirmBtn);
        await waitFor(() => {
            expect(defaultProps.updatePeriodState).toHaveBeenCalled();
        });
    });

    it('creates an "accounting_period_close" event when confirm button is clicked', async () => {
        render();

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');
        fireEvent.click(closePeriodBtn);

        const confirmBtn = screen.getByRole('button', {
            name: 'Yes, Close This Period',
        });
        fireEvent.click(confirmBtn);

        await waitFor(() => {
            expect(createAbacusEvent).toHaveBeenCalled();
        });
    });

    it('disables the close period button when the state is running', () => {
        const props = {
            ...defaultProps,
            closeState: {
                ...defaultProps.closeState,
                actionStatus: ABACUS_ACTION_STATUSES.RUNNING,
            },
        };

        render(props);

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');
        expect(closePeriodBtn).toBeDisabled();
    });

    it('disables the close period button when the state is complete', () => {
        const props = {
            ...defaultProps,
            closeState: {
                ...defaultProps.closeState,
                actionStatus: ABACUS_ACTION_STATUSES.COMPLETE,
            },
        };

        render(props);

        const closePeriodBtn = screen.getByTestId('closePeriodBtn');
        expect(closePeriodBtn).toBeDisabled();
    });
});
