import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { renderInAppContext } from '@theorchard/suite-testing';
import sample from 'lodash-es/sample';
import { ABACUS_ACTION_STATUSES } from '@theorchard/accounting-apps-shared';
import { ACCOUNTING_RUN_STATUSES as RUN_STATUSES } from 'src/constants';
import {
    MarkRunsAsCompleteAction,
    type MarkRunsAsCompleteActionPropTypes,
} from 'src/components/accounting-period/mark-runs-as-complete-action';
import type { AbacusFormattedAccountingRun } from 'src/types/accounting-period';

describe('<MarkRunsAsCompleteAction>', () => {
    const accountingRuns = {
        23: {
            id: 23,
            name: 'Priority 1 - Monthly',
            contractCount: null,
            date: null,
            status: RUN_STATUSES.NO_ACTION_TAKEN,
        },
        17: {
            id: 17,
            name: 'Priority 2 - Monthly',
            contractCount: null,
            date: '01-15-2019',
            status: RUN_STATUSES.APPROVED,
        },
        19: {
            id: 19,
            name: 'Priority 3 - Monthly',
            contractCount: null,
            date: null,
            status: RUN_STATUSES.INVALID,
        },
        29: {
            id: 29,
            name: 'Priority 4 - Quarterly',
            contractCount: 18,
            date: null,
            status: RUN_STATUSES.SKIPPED,
        },
    };
    const { APPROVED, SKIPPED, INVALID } = RUN_STATUSES;
    const { COMPLETE } = ABACUS_ACTION_STATUSES;

    const approvedSkippedInvalidRuns = Object.values(accountingRuns).reduce(
        (obj: AbacusFormattedAccountingRun, run) => {
            obj[run.id] = {
                ...run,
                status: sample([APPROVED, SKIPPED, INVALID]),
            };
            return obj;
        },
        {}
    );

    const defaultProps = {
        abacusStateId: '1',
        actionStatus: ABACUS_ACTION_STATUSES.INIT,
        accountingRuns: approvedSkippedInvalidRuns,
        updatePeriodState: jest.fn().mockResolvedValue({}),
        setError: jest.fn(),
    };

    const render = (props: MarkRunsAsCompleteActionPropTypes) =>
        renderInAppContext(<MarkRunsAsCompleteAction {...props} />);

    describe('Mark run as complete button', () => {
        it(`renders disabled if run statuses are not ${APPROVED} or ${SKIPPED} or ${INVALID}`, () => {
            const disabledProps = { ...defaultProps, accountingRuns };
            render(disabledProps);
            expect(screen.getByTestId('markRunsAsCompleteBtn').disabled).toBe(
                true
            );
        });

        it(`renders enabled if run statuses are ${APPROVED} or ${SKIPPED} or ${INVALID}`, () => {
            render(defaultProps);
            expect(screen.getByTestId('markRunsAsCompleteBtn').disabled).toBe(
                false
            );
        });
    });

    describe('Popup modal', () => {
        it('opens when #markRunsAsCompleteBtn is clicked', async () => {
            render(defaultProps);

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

            await waitFor(() => {
                expect(
                    screen.getByTestId('MarkRunAsCompletePopupTestid')
                ).toBeTruthy();
            });
        });

        it(`does not render skipped messaging when NO runs are ${APPROVED}`, async () => {
            const approvedRunsOnly = Object.values(accountingRuns).reduce(
                (obj, run) => {
                    // eslint-disable-next-line no-param-reassign
                    obj[run.id] = { ...run, status: APPROVED };
                    return obj;
                },
                {}
            );

            const approvedProps = {
                ...defaultProps,
                accountingRuns: approvedRunsOnly,
            };
            render(approvedProps);

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

            await waitFor(() => {
                const skippedMessaging =
                    screen.queryByTestId('skippedMessages');
                expect(skippedMessaging).toBeFalsy();
            });
        });

        it(`renders skipped messaged when runs are ${SKIPPED}`, async () => {
            const skippedRunsOnly = Object.values(accountingRuns).reduce(
                (obj: AbacusFormattedAccountingRun, run) => {
                    // eslint-disable-next-line no-param-reassign
                    obj[run.id] = { ...run, status: SKIPPED };
                    return obj;
                },
                {}
            );

            const skippedRuns = {
                ...defaultProps,
                accountingRuns: skippedRunsOnly,
            };
            render(skippedRuns);

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

            const skippedMessaging =
                await screen.findByTestId('skippedMessages');
            expect(skippedMessaging).toBeTruthy();
        });

        it(`updates period action status to ${COMPLETE}
            when the confirm button is clicked`, async () => {
            render(defaultProps);

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

            const confirmButton = await screen.findByText(
                'Yes, Mark Runs As Complete'
            );
            fireEvent.click(confirmButton);

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