import React, { useEffect, useState } from 'react';
import {
    Alert,
    Button,
    Container,
    Form,
    FullscreenModal,
    Row,
    Col,
    useToast,
} from '@theorchard/suite-components';
import cx from 'classnames';
import { isEmpty, difference } from 'lodash-es';
import {
    AbacusContractMechDeductionAdminType,
    AbacusContractMechDeductionMechanicalType,
    AbacusContractMechDeductionTerritory,
} from 'src/apollo/definitions/globalTypes';
import { useCreateContractMechanicalDeductions } from 'src/apollo/mutations/contract-mechanical-deductions';
import {
    addContractMechanicalDeductionsMessage,
    CONTRACT_MECHANICAL_DEDUCTION_TERRITORIES,
} from 'src/apollo/type-constants/contract';
import { ContractMechanicalDeductionTerritory } from 'src/components/contract-mechanical-deduction-create/contract-mechanical-deduction-territory';
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 { CreateContractMechanicalDeductionsMutationVariables } from 'src/apollo/mutations/contract-mechanical-deductions/__generated__/create-contract-mechanical-deductions';
import type { GetContractQuery } from 'src/apollo/queries/contract/__generated__/get-contract';
import type { ContractMechanicalDeduction } from 'src/types/abacus-contract-mechanical-deduction';

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

export interface ContractMechanicalDeductionFullscreenModalPropTypes {
    contractId: string;
    isWorldWide: boolean;
    mechanicalDeductions: AbacusContractMechDeductions[] | null;
    // eslint-disable-next-line no-unused-vars
    setIsMechDeductionFullScreenModalOpen: (params: boolean) => void;
}

export const ContractMechanicalDeductionFullscreenModal: React.FC<
    ContractMechanicalDeductionFullscreenModalPropTypes
> = ({
    contractId,
    isWorldWide,
    mechanicalDeductions,
    setIsMechDeductionFullScreenModalOpen,
}) => {
    const defaultFormValues: ContractMechanicalDeduction = {
        adminFee: null,
        adminType: AbacusContractMechDeductionAdminType.CUSTOMER,
        isAdminFeeSelected: false,
        mechanicalType: [],
        territory: null,
    };

    const [contractMechanicalDeduction, setContractMechanicalDeduction] =
        useState<ContractMechanicalDeduction>(defaultFormValues);
    const [
        existingMechDeductionTerritories,
        setExistingMechDeductionTerritories,
    ] = useState<AbacusContractMechDeductionTerritory[]>([]);
    const [isSaving, setIsSaving] = useState<boolean>(false);
    const [errors, setErrors] = useState<Partial<ContractMechanicalDeduction>>(
        {}
    );
    const [isServerError, setIsServerError] = useState<boolean>(false);
    const toast = useToast();
    const addContractMechanicalDeductions =
        useCreateContractMechanicalDeductions(contractId);

    useEffect(() => {
        const territories = Object.values(
            CONTRACT_MECHANICAL_DEDUCTION_TERRITORIES
        ).map(territory => territory.value);

        const existingTerritories =
            mechanicalDeductions?.map(
                mechDeduction => mechDeduction?.territory
            ) || [];
        setExistingMechDeductionTerritories(existingTerritories);

        const nonSelectedTerritories = difference(
            territories,
            existingTerritories
        );

        if (!isEmpty(nonSelectedTerritories) && !isWorldWide)
            setContractMechanicalDeduction({
                ...contractMechanicalDeduction,
                territory: nonSelectedTerritories[0],
            });
        else
            setContractMechanicalDeduction({
                ...contractMechanicalDeduction,
                territory: null,
            });
    }, [mechanicalDeductions]);

    const isSaveButtonDisabled = () => {
        const isProductTypesSelected =
            (!isWorldWide &&
                contractMechanicalDeduction.territory !==
                    AbacusContractMechDeductionTerritory.USA) ||
            !isEmpty(contractMechanicalDeduction?.mechanicalType);
        const isAdminTypeSelected = Boolean(
            contractMechanicalDeduction?.adminType
        );
        const isTerritorySelected =
            isWorldWide || Boolean(contractMechanicalDeduction?.territory);
        const isAdminFeeSelected =
            !contractMechanicalDeduction?.isAdminFeeSelected ||
            Boolean(contractMechanicalDeduction?.adminFee);

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

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

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

        let variables: CreateContractMechanicalDeductionsMutationVariables = {
            adminFee: !contractMechanicalDeduction?.adminFee
                ? null
                : parseFloat(contractMechanicalDeduction.adminFee),
            adminType: contractMechanicalDeduction.adminType!,
            contractId,
            mechanicalType: contractMechanicalDeduction?.mechanicalType,
            isWorldWide,
        };

        if (!isWorldWide)
            variables = {
                ...variables,
                territory: contractMechanicalDeduction?.territory,
            };

        if (
            !isWorldWide &&
            contractMechanicalDeduction?.territory !==
                AbacusContractMechDeductionTerritory.USA
        )
            variables = {
                ...variables,
                mechanicalType: [
                    AbacusContractMechDeductionMechanicalType.PHYSICAL,
                ],
            };

        addContractMechanicalDeductions({ variables })
            .then(() => {
                toast(addContractMechanicalDeductionsMessage(isWorldWide));
                setIsMechDeductionFullScreenModalOpen(false);
            })
            .catch(() => {
                setIsServerError(true);
                setIsSaving(false);
            });
    };

    const modalTitle = isWorldWide ? (
        <span>
            Setup mechanical deductions
            <br />
            worldwide
        </span>
    ) : (
        <span>Setup a mechanical deduction</span>
    );

    const worldWideTerritoryText = (
        <div>
            <b>Canada</b> & <b>Rest Of The World</b> only accept mechanical
            deductions for <b>Physical</b> products.
        </div>
    );

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

    return (
        <FullscreenModal>
            <FullscreenModal.Header title="Add Mechanical Deduction">
                <Button
                    variant="secondary"
                    className="ContractMechanicalDeductionFullScreenModal-CancelButton"
                    onClick={() =>
                        isSaving
                            ? false
                            : setIsMechDeductionFullScreenModalOpen(false)
                    }
                    data-testid="cancelButton"
                >
                    Cancel
                </Button>
            </FullscreenModal.Header>
            <div
                className="ContractMechanicalDeductionFullScreenModal-HeaderTitle"
                data-testId="header-title"
            >
                {modalTitle}
            </div>
            <FullscreenModal.Body>
                <Container className="ContractMechanicalDeductionFullScreenModal-Container">
                    <Form className="ContractMechanicalDeductionForm">
                        {isWorldWide ? (
                            <Alert
                                testId="worldwide-territory-alert-text"
                                text={worldWideTerritoryText}
                                variant="information"
                            />
                        ) : (
                            <ContractMechanicalDeductionTerritory
                                existingMechDeductionTerritories={
                                    existingMechDeductionTerritories
                                }
                                contractMechanicalDeduction={
                                    contractMechanicalDeduction
                                }
                                setContractMechanicalDeduction={
                                    setContractMechanicalDeduction
                                }
                            />
                        )}
                        <br />
                        <ContractMechanicalDeductionFormFields
                            contractMechanicalDeduction={
                                contractMechanicalDeduction
                            }
                            setContractMechanicalDeduction={
                                setContractMechanicalDeduction
                            }
                            errors={errors}
                            setErrors={setErrors}
                            setIsServerError={setIsServerError}
                        />
                        <Row>
                            <Col>
                                {isServerError && (
                                    <Alert
                                        testId="error-alert"
                                        variant="error"
                                        text={serverErrorMsg}
                                    />
                                )}
                            </Col>
                        </Row>
                        <Row>
                            <Col>
                                <div
                                    className={cx({
                                        'ContractMechanicalDeductionForm-SaveButton': true,
                                        'ContractMechanicalDeductionForm-SaveButton-disabled':
                                            isSaveButtonDisabled() ||
                                            isServerError,
                                        'ContractMechanicalDeductionForm-SaveButton-enabled':
                                            !isSaveButtonDisabled() &&
                                            !isServerError,
                                    })}
                                >
                                    <Button
                                        disabled={
                                            isSaveButtonDisabled() ||
                                            isSaving ||
                                            isServerError
                                        }
                                        onClick={() => saveHandler()}
                                        variant="primary"
                                    >
                                        Save
                                    </Button>
                                </div>
                            </Col>
                        </Row>
                    </Form>
                </Container>
            </FullscreenModal.Body>
        </FullscreenModal>
    );
};
