import React, { useCallback, useEffect, useState } from 'react';
import './styles.scss';
import {
    Alert,
    Button,
    FullscreenModal,
    Modal,
    useFullscreenModal,
} from '@theorchard/suite-components';
import { isArray } from 'lodash-es';
import { useHistory, useParams } from 'react-router-dom';
import type { EarningsTransferModalScreen } from 'src/apollo/type-constants/contract-earnings-transfer';
import {
    EARNINGS_TRANSFER_MODAL_SCREENS,
    EARNINGS_TRANSFER_TYPES_LABELS,
} from 'src/apollo/type-constants/contract-earnings-transfer';
import { getContractDetail } from 'src/urls/frontend-royalties';
import { useCreateHandler } from 'src/hooks/contract-earnings-transfer/create-contract-earnings-transfer';
import { useUpdateHandler } from 'src/hooks/contract-earnings-transfer/update-contract-earnings-transfer';
import { ContractEarningsTransferTypeScreen } from './contract-earnings-transfer-type-screen';
import {
    ContractEarningsTransferConfigScreen,
    hasTotalPercentageError,
} from './contract-earnings-transfer-config-screen';
import {
    AbacusEarningsTransferRateTypes,
    AbacusEarningsTransferSources,
    AbacusEarningsTransferTypes,
} from 'src/apollo/definitions/globalTypes';
import { validateAmount } from './contract-earnings-transfer-config-screen-columns';
import { useEarningsTransferById } from 'src/apollo/queries/earnings-transfer';
import {
    createEmptyRow,
    toTransferRow,
    toTransferType,
    type TransferRow,
} from 'src/types/abacus-contract-earnings-transfer';

const isRowValid = (row: TransferRow): boolean =>
    !!row.toContractId &&
    row.transferAmount !== '' &&
    row.rateType !== undefined &&
    row.input !== undefined &&
    row.active !== undefined &&
    validateAmount(row.transferAmount, row.rateType) === undefined;

const isFormValid = (
    transferType: AbacusEarningsTransferTypes | undefined,
    rows: TransferRow[]
): boolean =>
    !!transferType &&
    rows.length > 0 &&
    rows.every(isRowValid) &&
    !hasTotalPercentageError(rows);

const getModalTitleForTransferType = (
    transferType: AbacusEarningsTransferTypes
) => {
    const label = EARNINGS_TRANSFER_TYPES_LABELS[transferType].name;

    switch (transferType) {
        case AbacusEarningsTransferTypes.RECLASS:
            return 'Set Up Terms for Balance Transfers';
        case AbacusEarningsTransferTypes.TRANSFER:
            return 'Set Up Terms for Income Transfers';
        default:
            return `Set Up Terms for ${label} Transfers`;
    }
};

export const ContractEarningsTransferFullScreenModal: React.FC = () => {
    const { contractId, earningsTransferId } = useParams<{
        contractId: string;
        earningsTransferId?: string;
    }>();
    const history = useHistory();
    const { close } = useFullscreenModal();

    const closeModal = () => {
        close(() => history.push(getContractDetail(contractId)));
    };

    const [cancelModalOpen, setCancelModalOpen] = useState(false);
    const closeCancelModal = () => {
        setCancelModalOpen(false);
    };

    const [modalScreen, setModalScreen] = useState<EarningsTransferModalScreen>(
        EARNINGS_TRANSFER_MODAL_SCREENS.SELECT_TYPE
    );
    const [transferType, setTransferType] = useState<
        AbacusEarningsTransferTypes | undefined
    >(undefined);
    const [rows, setRows] = useState<TransferRow[]>([
        createEmptyRow(contractId),
    ]);
    const [editRow, setEditRow] = useState<TransferRow | null>(null);
    const [serverError, setServerError] = useState<string | null>(null);
    const [isSaving, setIsSaving] = useState(false);

    const isEditMode = !!earningsTransferId;
    const { data: editData, loading: editLoading } = useEarningsTransferById(
        earningsTransferId || '',
        !isEditMode
    );

    const createHandler = useCreateHandler(contractId);
    const updateHandler = useUpdateHandler(contractId);

    useEffect(() => {
        const earningsTransfer = editData?.abacusEarningsTransfer;

        if (earningsTransfer) {
            setTransferType(toTransferType(earningsTransfer.transferType));
            setModalScreen(EARNINGS_TRANSFER_MODAL_SCREENS.CONFIGURE);
            setEditRow(toTransferRow(earningsTransfer));
        }
    }, [editData]);

    const handleRowChange = useCallback(
        (index: number, updated: Partial<TransferRow>) => {
            setRows(prev =>
                prev.map((row, i) =>
                    i === index ? { ...row, ...updated } : row
                )
            );
        },
        []
    );

    const handleAddRow = () => {
        setRows(prev => [...prev, createEmptyRow(contractId)]);
    };

    const handleDeleteRow = (index: number) => {
        setRows(prev => prev.filter((_, i) => i !== index));
    };

    const handleResetRows = () => {
        setRows([createEmptyRow(contractId)]);
    };

    const handleTransferTypeChange = (
        type: AbacusEarningsTransferTypes | undefined
    ) => {
        setTransferType(type);

        // NOTE: When creating Balance Transfers (i.e. "Reclass") we want to
        // default some fields. The corresponding inputs will be disabled.
        if (type === AbacusEarningsTransferTypes.RECLASS) {
            handleRowChange(0, {
                rateType: AbacusEarningsTransferRateTypes.PERCENT,
                transferAmount: '100',
                input: AbacusEarningsTransferSources.CLOSING_BALANCE,
            });
        }
    };

    const handleSave = async () => {
        if (!transferType) return;
        setIsSaving(true);
        setServerError(null);
        try {
            if (isEditMode) {
                await updateHandler(earningsTransferId, transferType, rows[0]);
            } else {
                await createHandler(transferType, rows);
            }

            history.push(getContractDetail(contractId));
        } catch (e) {
            if (e instanceof Error) {
                setServerError(
                    `Error: ${e.message}. Failed to create transfer of earnings.`
                );
            } else if (isArray(e)) {
                setServerError(
                    `Error: ${JSON.stringify(e[0])}. Failed to create transfer of earnings.`
                );
            } else {
                setServerError(
                    `Error: ${String(e)}. Failed to create transfer of earnings.`
                );
            }
        } finally {
            setIsSaving(false);
        }
    };

    const isOnConfigureScreen =
        modalScreen === EARNINGS_TRANSFER_MODAL_SCREENS.CONFIGURE;
    const isSaveEnabled =
        isOnConfigureScreen && isFormValid(transferType, rows) && !isSaving;

    const transferTypeDescription = transferType
        ? EARNINGS_TRANSFER_TYPES_LABELS[transferType].description
        : '';

    const modalTitle =
        isOnConfigureScreen && transferType
            ? getModalTitleForTransferType(transferType)
            : 'Set Up Terms for Transfer of Earnings';

    const modalSubtitle = isOnConfigureScreen
        ? transferTypeDescription
        : 'Transfer balances from the current contract to one or more  contracts';

    return (
        <FullscreenModal
            layout="fluid"
            className="ContractEarningsTransferFullScreenModal"
        >
            <Modal
                isOpen={cancelModalOpen}
                onRequestClose={closeCancelModal}
                header="Are you sure you want to exit?"
                confirmButtonProps={{
                    onClick: () => {
                        closeModal();
                    },
                }}
                confirmTitle="Exit without saving"
                cancelButtonProps={{
                    title: 'Continue editing',
                    onClick: closeCancelModal,
                }}
            >
                Exiting now will cancel the creation of these transfer terms.
            </Modal>
            <FullscreenModal.Header title="Set Up Terms for Transfer of Earnings Calculations">
                <Button
                    variant="secondary"
                    onClick={() => setCancelModalOpen(true)}
                    className="ContractEarningsTransferFullScreenModal-CancelButton"
                    data-testid="earningsTransferCancelButton"
                >
                    Cancel
                </Button>
                <Button
                    variant="primary"
                    disabled={!isSaveEnabled}
                    onClick={handleSave}
                    className="ContractEarningsTransferFullScreenModal-CreateButton"
                    data-testid="earningsTransferSaveButton"
                >
                    {isEditMode ? ' Save' : 'Create'}
                </Button>
            </FullscreenModal.Header>
            <FullscreenModal.Title title={modalTitle}>
                {modalSubtitle}
            </FullscreenModal.Title>
            <FullscreenModal.Body>
                {serverError && (
                    <Alert
                        variant="error"
                        text={
                            <span>
                                {serverError}
                                <br />
                                &nbsp;Please contact the Abacus team.
                            </span>
                        }
                    />
                )}
                <ContractEarningsTransferTypeScreen
                    isVisible={
                        !editLoading &&
                        modalScreen ===
                            EARNINGS_TRANSFER_MODAL_SCREENS.SELECT_TYPE
                    }
                    transferType={transferType}
                    onTransferTypeChange={handleTransferTypeChange}
                    setModalScreen={setModalScreen}
                />
                <ContractEarningsTransferConfigScreen
                    isVisible={
                        !editLoading &&
                        modalScreen ===
                            EARNINGS_TRANSFER_MODAL_SCREENS.CONFIGURE
                    }
                    isEditMode={isEditMode}
                    rows={rows}
                    editRow={editRow}
                    transferType={transferType}
                    onRowChange={handleRowChange}
                    onAddRow={handleAddRow}
                    onDeleteRow={handleDeleteRow}
                    onResetRows={handleResetRows}
                    setModalScreen={setModalScreen}
                />
            </FullscreenModal.Body>
        </FullscreenModal>
    );
};
