import React, {
    useContext,
    useEffect,
    useRef,
    useState,
    type Dispatch,
    type SetStateAction,
} from 'react';
import { Button, LoadingSpinner } from '@theorchard/suite-components';
import ApproveAccountingRunModal from 'src/components/accounting-run-list/approve-accounting-run-modal';
import { ABACUS_ACTION_STATUSES as ACTION_STATUSES } from '@theorchard/accounting-apps-shared';
import {
    ACCOUNTING_PERIOD_STATUSES as PERIOD_STATUSES,
    ACCOUNTING_RUN_ACTIONS as RUN_ACTIONS,
    ACCOUNTING_RUN_STATUSES as RUN_STATUSES,
} from 'src/constants';
import { AccountingRunContext } from 'src/contexts/accounting-run-context';
import type { AbacusFormattedAccountingRun } from 'src/types/accounting-period';

/* eslint-disable key-spacing */
const actionTransitionMap = {
    [RUN_ACTIONS.CREATE]: RUN_STATUSES.WAITING_TO_RUN,
    [RUN_ACTIONS.APPROVE]: RUN_STATUSES.APPROVING,
    [RUN_ACTIONS.INVALIDATE]: RUN_STATUSES.INVALID,
    [RUN_ACTIONS.SKIP]: RUN_STATUSES.SKIPPED,
    [RUN_ACTIONS.UNDO]: RUN_STATUSES.NO_ACTION_TAKEN,
};
/* eslint-enable key-spacing */

export interface AccountingRunActionButtonPropTypes {
    accountingRunId: number;
    action: string;
    isUpdatingRun: boolean;
    setUpdatingRun: Dispatch<SetStateAction<boolean>>;
}

export const AccountingRunActionButton: React.FC<
    AccountingRunActionButtonPropTypes
> = ({ accountingRunId, action, isUpdatingRun, setUpdatingRun }) => {
    const {
        accountingPeriodDetail: { accountingPeriodStatus },
        accountingRuns,
        arePeriodActionsComplete,
        closePeriodActionStatus,
    } = useContext(AccountingRunContext);

    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
    const newStatus = actionTransitionMap[action];
    const periodStatus = accountingPeriodStatus;
    const { updateRunStatus } = useContext(AccountingRunContext);
    const validClosePeriodStatuses = [
        ACTION_STATUSES.RUNNING,
        ACTION_STATUSES.COMPLETE,
    ];

    const isMounted = useRef(true);

    const isDisabled = () => {
        if (action == RUN_ACTIONS.APPROVE) {
            const areRunsApproving = (
                Object.values(
                    accountingRuns
                ) as AbacusFormattedAccountingRun[string][]
            ).some(run => run.status === RUN_STATUSES.APPROVING);
            return (
                areRunsApproving ||
                periodStatus !== PERIOD_STATUSES.LOCKED ||
                !arePeriodActionsComplete
            );
        }

        if ([RUN_ACTIONS.CREATE, RUN_ACTIONS.SKIP].includes(action))
            return (
                periodStatus !== PERIOD_STATUSES.LOCKED ||
                !arePeriodActionsComplete
            );

        if (action === RUN_ACTIONS.UNDO)
            return (
                periodStatus === PERIOD_STATUSES.CLOSED ||
                validClosePeriodStatuses.includes(closePeriodActionStatus)
            );
    };

    const updateAction = async () => {
        setIsLoading(true);
        setUpdatingRun(true);
        try {
            await updateRunStatus(accountingRunId, newStatus)
                .then(() => {
                    setIsLoading(false);
                    setUpdatingRun(false);
                })
                .catch(() => {
                    setIsLoading(false);
                    setUpdatingRun(false);
                });
        } finally {
            if (isMounted.current) {
                setIsLoading(false);
            }
        }
    };

    useEffect(() => {
        isMounted.current = true;

        return () => {
            isMounted.current = false;
        };
    }, []);

    const confirmOrUpdate = () =>
        action === RUN_ACTIONS.APPROVE ? setIsModalOpen(true) : updateAction();

    return (
        <span>
            <Button
                className={`AccountingRun-actionButton ${action}`}
                data-testid={`${action.toLowerCase()}AccountingRun-${accountingRunId}`}
                disabled={isDisabled() || isUpdatingRun}
                id={`${action.toLowerCase()}AccountingRun-${accountingRunId}`}
                onClick={() => confirmOrUpdate()}
                size="sm"
                variant="quartenary"
            >
                {isLoading && (
                    <div className="actionButtonSpinner">
                        <LoadingSpinner show size={12} />
                    </div>
                )}
                <span
                    className={isLoading ? 'AccountingRun-hide-actionText' : ''}
                >
                    {action}
                </span>
            </Button>
            <ApproveAccountingRunModal
                isApproveAccountingRunModalOpen={isModalOpen}
                setIsApproveAccountingRunModalOpen={setIsModalOpen}
                isSaveButtonDisabled={isUpdatingRun}
                saveHandler={updateAction}
            />
        </span>
    );
};

export default React.memo(AccountingRunActionButton);
