import React, {
    useState,
    useEffect,
    type Dispatch,
    type SetStateAction,
} from 'react';
import { Alert, Modal, Form, Field } from '@theorchard/suite-components';
import { isEmpty, trim } from 'lodash-es';
import { useCreateAccountingPeriod } from 'src/apollo/mutations/accounting-period';
import ContractTypeSelect from 'src/components/shared/contract-type-select';
import { CONTRACT_TYPES } from 'src/constants';
import { CONTRACT_TYPE_MAP } from 'src/apollo/type-constants/contract';
import { accountingPeriodFormValidation } from 'src/utils/form-validations/accounting-period-form-validation';
import type {
    AccountingPeriodFormFields,
    AccountingPeriodFormErrors,
} from 'src/types/accounting-period-form';
import type { AbacusCurrentStatementPeriod } from 'src/types/statement-period';

export interface AccountingPeriodFormModalPropsTypes {
    isAccountingPeriodFormModalOpen: boolean;
    onCloseHandler: () => void;
    currentStatementPeriod: Pick<
        AbacusCurrentStatementPeriod,
        'statementPeriodId' | 'statementPeriodName'
    >;
    setPage: Dispatch<SetStateAction<number>>;
}

export const AccountingPeriodFormModal: React.FC<
    AccountingPeriodFormModalPropsTypes
> = ({
    isAccountingPeriodFormModalOpen,
    onCloseHandler,
    currentStatementPeriod,
    setPage,
}) => {
    const { statementPeriodId, statementPeriodName } = currentStatementPeriod;
    const [formData, setFormData] = useState<AccountingPeriodFormFields>({
        statementPeriodId,
        contractType: '',
        accountingPeriodName: '',
    });
    const [formErrors, setFormErrors] = useState<
        Partial<AccountingPeriodFormErrors> | undefined
    >(undefined);
    const [isSaveButtonDisabled, setIsSaveButtonDisabled] = useState(true);
    const [isCreatingAccountingPeriod, setIsCreatingAccountingPeriod] =
        useState(false);
    const [serverError, setServerError] = useState<string>('');
    const addAccountingPeriod = useCreateAccountingPeriod();

    const changeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
        const {
            target: { name, value },
        } = e;
        if (isEmpty(value)) {
            delete formData[name as keyof AccountingPeriodFormFields];
            setFormData({ ...formData });
        } else setFormData({ ...formData, [name]: value });

        setFormErrors({});
        setServerError('');
    };

    const saveNewAccountingPeriod = () => {
        setIsSaveButtonDisabled(true);
        setIsCreatingAccountingPeriod(true);
        const validationErrors = accountingPeriodFormValidation(formData);
        if (Object.keys(validationErrors).length > 0) {
            setIsSaveButtonDisabled(false);
            setIsCreatingAccountingPeriod(false);
            return setFormErrors(validationErrors);
        }

        setFormErrors({});

        const variables = {
            statementPeriodId: formData.statementPeriodId,
            contractType: formData.contractType,
            accountingPeriodName: trim(formData.accountingPeriodName),
        };

        addAccountingPeriod({ variables })
            .then(() => {
                onCloseHandler();
                setPage(0);
            })
            .catch(error => {
                if (Array.isArray(error))
                    setServerError(
                        `Error: ${JSON.stringify(error[0])}, Failed to create accounting period.`
                    );
                else
                    setServerError(
                        `Error: ${String(error)}, Failed to create accounting period.`
                    );
                setIsCreatingAccountingPeriod(false);
                setIsSaveButtonDisabled(false);
            });
    };

    useEffect(() => {
        if (isAccountingPeriodFormModalOpen) {
            setFormData({
                statementPeriodId,
                contractType: '',
                accountingPeriodName: '',
            });
            setFormErrors({});
            setServerError('');
        }
    }, [isAccountingPeriodFormModalOpen]);

    useEffect(() => {
        const assignedValues = Object.values(formData).filter(value => {
            if (typeof value === 'string') return value.trim() !== '';
            return value !== null && value !== undefined;
        });
        setIsSaveButtonDisabled(assignedValues.length !== 3);
    }, [formData]);

    const modalContent = (
        <div data-testid="AccountingPeriodFormModal">
            {serverError && (
                <div className="AccountingPeriodFormModal-Error">
                    <Alert variant="error" text={<span>{serverError}</span>} />
                </div>
            )}
            <Form.Group className="AccountingPeriodFormFields">
                <Field
                    controlId="ContractTypeSelect"
                    labelText="Contract Type"
                    errorMessage={
                        (formErrors as AccountingPeriodFormErrors)
                            ?.contractType || undefined
                    }
                    isRequired={true}
                >
                    <ContractTypeSelect
                        className="ContractTypeSelect"
                        id="ContractTypeSelect"
                        isClearable={false}
                        name="contractType"
                        onChange={(
                            e: Record<string, keyof typeof CONTRACT_TYPE_MAP>
                        ) =>
                            changeHandler({
                                target: {
                                    name: 'contractType',
                                    value: e.value,
                                },
                            } as any)
                        }
                        placeholder="Select"
                        removeOptions={[CONTRACT_TYPES.LEGACY_DISTRIBUTION]}
                        value={formData.contractType || ''}
                    />
                </Field>
                <Field
                    controlId="AccountingPeriodName"
                    labelText="Period Name"
                    errorMessage={
                        (formErrors as AccountingPeriodFormErrors)
                            ?.accountingPeriodName || undefined
                    }
                    isRequired={true}
                >
                    <input
                        className="form-control"
                        data-testid="accounting-period-name"
                        onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                            changeHandler(e)
                        }
                        name="accountingPeriodName"
                        placeholder="Enter Name"
                        type="text"
                        value={formData.accountingPeriodName || ''}
                    />
                </Field>
                <Field
                    controlId="StatementPeriod"
                    labelText="Statement Period"
                    errorMessage={
                        (formErrors as AccountingPeriodFormErrors)
                            ?.statementPeriodId || undefined
                    }
                >
                    <div
                        className="form-control statement-period disabled"
                        data-testid="input-statement-period"
                    >
                        {statementPeriodName}
                        <span className="current-label">
                            {statementPeriodId ? 'Current' : ''}
                        </span>
                    </div>
                </Field>
            </Form.Group>
        </div>
    );
    return (
        <Modal
            className="AccountingPeriodFormModal"
            isOpen={isAccountingPeriodFormModalOpen}
            onRequestClose={
                isCreatingAccountingPeriod ? () => false : onCloseHandler
            }
            testId="AccountingPeriodForm"
            title="New Accounting Period"
            confirmButtonProps={{
                disabled: isSaveButtonDisabled,
                variant: 'primary',
                loading: isCreatingAccountingPeriod,
                title: 'Create',
                onClick: () => saveNewAccountingPeriod(),
            }}
        >
            {modalContent}
        </Modal>
    );
};
