import React, { useEffect, useState } from 'react';
import {
    Alert,
    Col,
    Form,
    Row,
    Sidecar,
    useToast,
} from '@theorchard/suite-components';
import classNames from 'classnames';
import { isEmpty } from 'lodash-es';
import {
    AbacusContractMechDeductionAdminType,
    AbacusContractMechDeductionTerritory,
} from 'src/apollo/definitions/globalTypes';
import { useUpdateContractMechanicalDeduction } from 'src/apollo/mutations/contract-mechanical-deductions';
import {
    CONTRACT_MECHANICAL_DEDUCTION_TERRITORIES,
    UPDATE_CONTRACT_MECH_DEDUCTION_MSG,
} from 'src/apollo/type-constants/contract';
import { ContractMechanicalDeductionFormFields } from 'src/components/contract-mechanical-deduction-shared/contract-mechanical-deduction-form-fields';
import { contractMechanicalDeductionFormValidation } from 'src/utils/form-validations/contract-mechanical-deduction-form-validation';
import type { UpdateContractMechanicalDeductionMutationVariables } from 'src/apollo/mutations/contract-mechanical-deductions/__generated__/update-contract-mechanical-deduction';
import type { GetContractQuery } from 'src/apollo/queries/contract/__generated__/get-contract';
import type { ContractMechanicalDeduction } from 'src/types/abacus-contract-mechanical-deduction';
import './styles.scss';

type AbacusContract = NonNullable<GetContractQuery['abacusContract']>;
type AbacusContractMechDeductions =
    AbacusContract['mechanicalDeductions'] extends (infer T)[] | null
        ? T
        : null;

export interface ContractMechanicalDeductionSidecarPropTypes {
    mechanicalDeduction: AbacusContractMechDeductions;
    isSidecarOpen: boolean;
    setIsSidecarOpen: (params: boolean) => void;
}

export const ContractMechanicalDeductionSidecar: React.FC<
    ContractMechanicalDeductionSidecarPropTypes
> = ({ mechanicalDeduction, isSidecarOpen, setIsSidecarOpen }) => {
    const defaultFormValues: ContractMechanicalDeduction = {
        adminFee: null,
        adminType: AbacusContractMechDeductionAdminType.CUSTOMER,
        isAdminFeeSelected: false,
        mechanicalType: [],
        territory: AbacusContractMechDeductionTerritory.USA,
    };
    const [contractMechanicalDeduction, setContractMechanicalDeduction] =
        useState<ContractMechanicalDeduction>(defaultFormValues);
    const [errors, setErrors] = useState<Partial<ContractMechanicalDeduction>>(
        {}
    );
    const [isSaving, setIsSaving] = useState<boolean>(false);
    const [isServerError, setIsServerError] = useState<boolean>(false);
    const toast = useToast();
    const updateContractMechanicalDeduction =
        useUpdateContractMechanicalDeduction(mechanicalDeduction.contractId);

    const headerText = (
        <div
            className="EditContractMechanicalDeductionSidecar-Header"
            data-testid="EditContractMechanicalDeductionSidecarHeader"
        >
            Mechanical Deduction •{' '}
            {
                CONTRACT_MECHANICAL_DEDUCTION_TERRITORIES[
                    mechanicalDeduction.territory
                ].label
            }
        </div>
    );

    useEffect(() => {
        if (mechanicalDeduction) {
            setContractMechanicalDeduction({
                adminFee: mechanicalDeduction.adminFee
                    ? mechanicalDeduction.adminFee.toString()
                    : null,
                adminType: mechanicalDeduction.adminType,
                isAdminFeeSelected: Boolean(mechanicalDeduction.adminFee),
                mechanicalType: JSON.parse(
                    JSON.stringify(mechanicalDeduction.mechanicalType)
                ),
                territory: mechanicalDeduction.territory,
            });
        }
    }, [mechanicalDeduction, isSidecarOpen]);

    const isSaveButtonDisabled = () => {
        const isProductTypesSelected = !isEmpty(
            contractMechanicalDeduction.mechanicalType
        );
        const isAdminTypeSelected = Boolean(
            contractMechanicalDeduction.adminType
        );
        const isAdminFeeSelected =
            !contractMechanicalDeduction.isAdminFeeSelected ||
            Boolean(contractMechanicalDeduction.adminFee);

        return !(
            isProductTypesSelected &&
            isAdminTypeSelected &&
            isAdminFeeSelected
        );
    };

    const saveHandler = () => {
        setIsSaving(true);
        const errors = contractMechanicalDeductionFormValidation(
            contractMechanicalDeduction
        );

        if (Object.keys(errors).length > 0) {
            setErrors(errors);
            setIsSaving(false);
            return;
        }

        const variables: UpdateContractMechanicalDeductionMutationVariables = {
            adminFee: !contractMechanicalDeduction?.adminFee
                ? null
                : parseFloat(contractMechanicalDeduction.adminFee),
            adminType: contractMechanicalDeduction.adminType!,
            contractMechanicalDeductionId:
                mechanicalDeduction.contractMechanicalDeductionId,
            mechanicalType: contractMechanicalDeduction.mechanicalType,
        };

        updateContractMechanicalDeduction({ variables })
            .then(() => {
                setIsSidecarOpen(false);
                setIsSaving(false);
                toast(UPDATE_CONTRACT_MECH_DEDUCTION_MSG);
            })
            .catch(() => {
                setIsServerError(true);
                setIsSaving(false);
            });
    };

    const serverErrorMsg = (
        <div
            className="EditContractMechanicalDeductionSidecar-ErrorMsg"
            data-testid="EditContractMechanicalDeductionSidecar-ErrorMsg"
        >
            An error has occurred while updating contract mechanical deduction.
            Please <b>contact the Accounting Tech Team</b> to resolve this
            issue.
        </div>
    );

    const closeHandler = () => {
        if (isSaving) return false;
        else {
            setErrors({});
            setIsSidecarOpen(false);
            setIsServerError(false);
        }
    };

    return (
        <Sidecar
            className={classNames({
                EditContractMechanicalDeductionSidecar: true,
                EditContractMechanicalDeductionSidecarError: isServerError,
            })}
            confirmDisabled={
                isSaveButtonDisabled() || isSaving || isServerError
            }
            isOpen={isSidecarOpen}
            onConfirm={saveHandler}
            onRequestClose={closeHandler}
            testId="ContractMechanicalDeductionEditSidecar"
            title={headerText}
        >
            <Form className="ContractMechanicalDeductionForm">
                <ContractMechanicalDeductionFormFields
                    contractMechanicalDeduction={contractMechanicalDeduction}
                    isEditForm={true}
                    setContractMechanicalDeduction={
                        setContractMechanicalDeduction
                    }
                    errors={errors}
                    setErrors={setErrors}
                    setIsServerError={setIsServerError}
                />
                <Row>
                    <Col>
                        {isServerError && (
                            <Alert
                                testId="error-alert"
                                variant="error"
                                text={serverErrorMsg}
                            />
                        )}
                    </Col>
                </Row>
            </Form>
        </Sidecar>
    );
};
