import type { FC } from 'react';
import React, { useState } from 'react';
import { Alert, Button, Card } from '@theorchard/suite-components';
import { useCreateCloseBalanceEvent } from 'src/apollo/mutations/close-balance';
import { STATEMENT_PERIOD_ACTIONS } from 'src/constants';
import { PaymentEntityStatus } from 'src/types/payment-entity-status-indicator';
import { getAdjustmentsPage } from 'src/urls/frontend-royalties';
import { isActionComplete } from 'src/utils/action-states';
import { getActionStateByEventName } from 'src/utils/actionStates';
import { StepIndicator } from './step-indicator';
import type { GetStatementPeriodQuery } from 'src/apollo/queries/statement-periods/__generated__/statement-period';
import { ABACUS_ACTION_STATUSES } from '@theorchard/accounting-apps-shared';

type AbacusStatementPeriod = NonNullable<
    GetStatementPeriodQuery['abacusStatementPeriod']
>;
type AbacusStatementPaymentEntity = NonNullable<
    AbacusStatementPeriod['paymentEntities'][0]
>;

export interface BalanceProps {
    paymentEntity: AbacusStatementPaymentEntity;
    statementPeriod: AbacusStatementPeriod;
    setCloseBalanceStatus: React.Dispatch<
        React.SetStateAction<PaymentEntityStatus | undefined>
    >;
}
export const TERM_CLOSE_BALANCE_ERR_ALERT_TITLE = `This balance can't be closed`;
export const TERM_PENDING_ADJUSTMENTS_ALERT =
    'Before closing balances for these Contracts, please apply all adjustments that could affect their balances this Statement Period.';
export const TERM_RELEASE_RESERVES_ALERT =
    'Before closing balances for these Contracts, please release all reserves that could affect their balances this Statement Period.';
export const TERM_ADJUSTMENTS_LINK_TEXT = 'View and apply adjustments';
export const TERM_BODY_MESSAGE_INIT = 'The balance is ready to be closed';
export const TERM_BODY_MESSAGE_RUNNING = 'The close balance action is running';
export const TERM_BODY_MESSAGE_COMPLETE = 'The balance is closed';

const Balance: FC<BalanceProps> = ({
    paymentEntity,
    setCloseBalanceStatus,
    statementPeriod,
}) => {
    const statementPeriodPaymentEntityId =
        paymentEntity.statementPeriodPaymentEntityId;
    const statementPeriodId = paymentEntity.statementPeriodId;
    const [closeBalanceError, setCloseBalanceError] = useState();

    const {
        createCloseBalanceEvent,
        loading: isCreateCloseBalanceEventLoading,
    } = useCreateCloseBalanceEvent(
        statementPeriodPaymentEntityId,
        statementPeriodId
    );

    const closeBalanceActionState = getActionStateByEventName(
        STATEMENT_PERIOD_ACTIONS.CLOSE_BALANCE,
        paymentEntity?.actionStates
    );

    const statementPeriodHasPandingAdjustments =
        statementPeriod?.paymentEntities.some(
            paymentEntity => paymentEntity.pendingAdjustments.totalCount > 0
        );
    const paymentEntityHasPendingAdjustments =
        paymentEntity.pendingAdjustments.totalCount > 0;

    const physicalReservesAreReleased = isActionComplete(
        statementPeriod?.actionStates,
        STATEMENT_PERIOD_ACTIONS.RELEASE_RESERVES
    );

    const statementPeriodClosed = isActionComplete(
        statementPeriod?.actionStates,
        STATEMENT_PERIOD_ACTIONS.STATEMENT_PERIOD_CLOSE
    );

    const isCloseBalanceBlocked =
        (statementPeriodHasPandingAdjustments &&
            paymentEntityHasPendingAdjustments) ||
        !physicalReservesAreReleased ||
        statementPeriodClosed;

    const closeBalanceActionStatus = closeBalanceActionState?.actionStatus;

    const isCloseBalanceDisabled =
        isCloseBalanceBlocked ||
        isCreateCloseBalanceEventLoading ||
        closeBalanceActionState?.actionStatus !== ABACUS_ACTION_STATUSES.INIT;

    const closeBalance = () => {
        const variables = {
            statementPeriodPaymentEntityId: statementPeriodPaymentEntityId,
            statementPeriodId: statementPeriodId,
        };

        createCloseBalanceEvent({ variables }).catch(err => {
            setCloseBalanceError(err[0].message || JSON.stringify(err));
        });
    };

    (function () {
        if (isCloseBalanceBlocked) {
            return setCloseBalanceStatus(PaymentEntityStatus.BLOCKED);
        }
        if (
            closeBalanceActionStatus === ABACUS_ACTION_STATUSES.INIT ||
            closeBalanceActionStatus === ABACUS_ACTION_STATUSES.RUNNING
        ) {
            return setCloseBalanceStatus(PaymentEntityStatus.IN_PROGRESS);
        }
        if (
            closeBalanceActionStatus === ABACUS_ACTION_STATUSES.APPROVED ||
            closeBalanceActionStatus === ABACUS_ACTION_STATUSES.COMPLETE
        ) {
            return setCloseBalanceStatus(PaymentEntityStatus.COMPLETE);
        }
    })();

    const renderStepIndicator = () => {
        const defaultView = (
            <StepIndicator variant="error" glyphIconName="close" />
        );
        if (!closeBalanceActionStatus) {
            return defaultView;
        }

        switch (closeBalanceActionStatus) {
            case ABACUS_ACTION_STATUSES.INIT:
            case ABACUS_ACTION_STATUSES.RUNNING:
                return (
                    <StepIndicator variant="neutral" glyphIconName="check" />
                );
            case ABACUS_ACTION_STATUSES.APPROVED:
            case ABACUS_ACTION_STATUSES.COMPLETE:
                return (
                    <StepIndicator variant="success" glyphIconName="check" />
                );
            default:
                return defaultView;
        }
    };

    const renderCloseBalanceBodyMessage = () => {
        switch (closeBalanceActionStatus) {
            case ABACUS_ACTION_STATUSES.INIT:
                return TERM_BODY_MESSAGE_INIT;
            case ABACUS_ACTION_STATUSES.RUNNING:
                return TERM_BODY_MESSAGE_RUNNING;
            case ABACUS_ACTION_STATUSES.COMPLETE:
                return TERM_BODY_MESSAGE_COMPLETE;
            default:
                return null;
        }
    };

    return (
        <Card.Body>
            <div className="d-flex justify-content-between">
                <div className="d-flex align-items-center">
                    {renderStepIndicator()}
                    <div className="step-name">Balance</div>
                </div>
                <Button
                    data-testid="closeBalanceButton"
                    disabled={isCloseBalanceDisabled}
                    onClick={closeBalance}
                    variant="secondary"
                >
                    Close
                </Button>
            </div>
            <div className="card-body-message">
                {renderCloseBalanceBodyMessage()}
            </div>
            {closeBalanceError && (
                <Alert
                    variant="error"
                    title={TERM_CLOSE_BALANCE_ERR_ALERT_TITLE}
                    text={closeBalanceError}
                />
            )}
            {statementPeriodHasPandingAdjustments &&
                paymentEntityHasPendingAdjustments && (
                    <Alert
                        variant="error"
                        title={TERM_CLOSE_BALANCE_ERR_ALERT_TITLE}
                        text={TERM_PENDING_ADJUSTMENTS_ALERT}
                        link={{
                            text: TERM_ADJUSTMENTS_LINK_TEXT,
                            to: getAdjustmentsPage,
                        }}
                    />
                )}
            {!physicalReservesAreReleased && (
                <Alert
                    variant="error"
                    title={TERM_CLOSE_BALANCE_ERR_ALERT_TITLE}
                    text={TERM_RELEASE_RESERVES_ALERT}
                />
            )}
        </Card.Body>
    );
};

export default Balance;
