import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
    MultiSelect,
    Modal,
    Field,
    Select,
    Alert,
} from '@theorchard/suite-components';
import { useParams } from 'react-router-dom';
import { AbacusContractType } from 'src/apollo/definitions/globalTypes';
import { useSearchableContractList } from 'src/apollo/queries/contract';
import { useContractTermsByContractId } from 'src/apollo/queries/contract-term';
import { copyContractTermConditionsFormValidations } from 'src/utils/form-validations/contract-term-form-validation';
import type { AbacusContractItem } from 'src/types/abacus-contract-search-item';
import type { AbacusDistroContractTermCondition } from 'src/types/abacus-contract-term';

export interface CopyTermConditionsFormPopupPropType {
    contractType: AbacusContractType;
    isCopyConditionsModalOpen: boolean;
    // eslint-disable-next-line no-unused-vars
    setIsCopyConditionsModalOpen: (val: boolean) => void;
    conditions: AbacusDistroContractTermCondition[];
    // eslint-disable-next-line no-unused-vars
    setConditions: (newConditions: AbacusDistroContractTermCondition[]) => void;
}

interface ContractOption {
    label: string;
    value: string;
    raw: AbacusContractItem;
}

interface SearchResponse {
    data: ContractOption[];
}

export const CopyTermConditionsFormPopup: React.FC<
    CopyTermConditionsFormPopupPropType
> = ({
    contractType,
    isCopyConditionsModalOpen,
    setIsCopyConditionsModalOpen,
    conditions,
    setConditions,
}) => {
    const { contractTermId: currentContractTermId } = useParams<{
        contractTermId: string;
    }>();

    const [contractTermIds, setContractTermIds] = useState<string[]>([]);
    const [isCopyingConditions, setIsCopyingConditions] = useState(false);
    const [errors, setErrors] = useState<Record<string, string>>({});
    const [selectedContractOption, setSelectedContractOption] = useState<
        ContractOption | undefined
    >(undefined);

    const isDistroContract = contractType === AbacusContractType.DISTRIBUTION;
    const isSaveButtonDisabled =
        isCopyingConditions ||
        (isDistroContract && contractTermIds.length === 0);

    const { data: contractTerms, getContractsTermsByContractId } =
        useContractTermsByContractId();

    const { searchContracts } = useSearchableContractList();
    const contractId = selectedContractOption?.raw.contractId;

    useEffect(() => {
        if (contractId) {
            void getContractsTermsByContractId(contractId);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [contractId]);

    const {
        dropdownOptions: contractTermsDropdownOptions,
        termConditionsMap: contractTermsConditions,
    } = useMemo(() => {
        const dropdownOptions: { label: string; value: string }[] = [];
        const termConditionsMap: Record<
            string,
            AbacusDistroContractTermCondition[]
        > = {};

        if (!contractTerms?.abacusContractTerms)
            return { dropdownOptions, termConditionsMap };

        for (const term of contractTerms.abacusContractTerms) {
            if (term.contractTermId === currentContractTermId) continue;

            dropdownOptions.push({
                label: term.contractTermName
                    ? `${term.contractTermName} - ${term.contractTermId}`
                    : term.contractTermId,
                value: term.contractTermId,
            });

            termConditionsMap[term.contractTermId] = (
                term.conditions || []
            ).map(condition => {
                const {
                    countries = [],
                    stores = [],
                    transactionTypes = [],
                } = condition.conditions ?? {};
                return {
                    ...condition,
                    termRate:
                        condition.termRate !== undefined &&
                        condition.termRate !== null
                            ? String(condition.termRate)
                            : '',
                    conditions: {
                        countries: Array.isArray(countries) ? countries : [],
                        stores: Array.isArray(stores) ? stores : [],
                        transactionTypes: Array.isArray(transactionTypes)
                            ? transactionTypes
                            : [],
                    },
                };
            });
        }

        return { dropdownOptions, termConditionsMap };
    }, [contractTerms, currentContractTermId]);

    const saveButtonText = () =>
        isDistroContract
            ? isCopyingConditions
                ? 'Copying'
                : 'Copy'
            : 'Update';

    const toContractOption = (item: AbacusContractItem): ContractOption => ({
        label: `${item.contractName} (${item.contractId})`,
        value: item.contractId.toString(),
        raw: item,
    });

    const performContractSearch = async (
        term = ''
    ): Promise<SearchResponse> => {
        if (!term) return { data: [] };

        try {
            const result = await searchContracts(term, contractType);
            const rawItems =
                result.data?.abacusContracts?.items?.filter(
                    (item): item is AbacusContractItem => !!item
                ) || [];
            return { data: rawItems.map(toContractOption) };
        } catch (err) {
            console.error('Contract search failed:', err);
            return { data: [] };
        }
    };

    const handleContractChange = (option?: ContractOption): void => {
        setSelectedContractOption(option);
    };

    const updateHandler = useCallback(async () => {
        const validationErrors = copyContractTermConditionsFormValidations({
            contractId: contractId || '',
            contractTermId: contractTermIds,
        });

        if (Object.keys(validationErrors).length > 0) {
            setErrors(validationErrors);
            return;
        }

        setIsCopyingConditions(true);
        setErrors({});

        try {
            const currentConditionsLength = conditions.length;
            const allCopiedConditions: AbacusDistroContractTermCondition[] = [];

            contractTermIds.forEach(termId => {
                const copiedConditionsForTerm =
                    contractTermsConditions[termId] || [];

                copiedConditionsForTerm.forEach(condition => {
                    const newCondition: AbacusDistroContractTermCondition = {
                        contractTermConditionId: '',
                        contractTermId: '',
                        priority:
                            currentConditionsLength +
                            allCopiedConditions.length +
                            1,
                        termRate: condition.termRate ?? null,
                        conditions: condition.conditions,
                        contractTermConditionName: null,
                    };
                    allCopiedConditions.push(newCondition);
                });
            });

            setConditions([...conditions, ...allCopiedConditions]);
            setIsCopyConditionsModalOpen(false);
            setSelectedContractOption(undefined);
            setContractTermIds([]);
        } catch (error) {
            console.error('Error copying term conditions:', error);
            setErrors({
                general: 'Failed to copy conditions. Please try again.',
            });
        } finally {
            setIsCopyingConditions(false);
        }
    }, [
        contractId,
        contractTermIds,
        conditions,
        contractTermsConditions,
        setConditions,
        setIsCopyConditionsModalOpen,
    ]);

    const selectedTermOptions = contractTermsDropdownOptions.filter(opt =>
        contractTermIds.includes(opt.value)
    );

    const closeModalHandler = () => {
        setIsCopyConditionsModalOpen(false);
        setSelectedContractOption(undefined);
        setContractTermIds([]);
        setErrors({});
    };

    const handleMultiSelectChange = useCallback(
        (selected: { value: string }[]) => {
            setContractTermIds(selected.map(opt => opt.value));
        },
        []
    );

    return (
        <Modal
            className="ContractTermsDistroFormFields-ContractTermsConditionsForm-CopyConditions SuiteButtonOverrides"
            title="Copy Conditions From ..."
            isOpen={isCopyConditionsModalOpen}
            onRequestClose={closeModalHandler}
            onConfirm={updateHandler}
            confirmTitle={saveButtonText()}
            cancelTitle="Cancel"
            testId="copyConditionsModal"
            hideCancelButton={isCopyingConditions}
            confirmDisabled={isSaveButtonDisabled || isCopyingConditions}
        >
            {errors.message && (
                <Alert
                    variant="error"
                    text={
                        <span>
                            {errors.message ||
                                'An error occurred while fetching the contract term.'}
                            <br />
                            &nbsp;Please contact the Abacus team.
                        </span>
                    }
                />
            )}
            You can copy conditions from any other contract. They will be added
            to the Terms currently open on this page.
            <Field
                controlId="contractTermDistroCopyConditions"
                labelText="Contract"
                testId="contractTermDistroCopyConditions"
            >
                <Select<ContractOption>
                    placeholder="Search for Contract"
                    onChange={handleContractChange}
                    onLoadOptions={performContractSearch}
                    selectedValue={selectedContractOption}
                    menuWidth="100%"
                />
            </Field>
            <Field
                controlId="contractTermDistroCopyConditionsHeader"
                labelText="Term"
                testId="contractTermDistroCopyConditionsHeader"
            >
                <MultiSelect
                    className="SelectTerms"
                    name="contractTermsDropdown"
                    options={contractTermsDropdownOptions}
                    placeholder="Select Term(s)"
                    onChange={handleMultiSelectChange}
                    selectedValue={selectedTermOptions}
                    menuWidth="100%"
                    disabled={!contractId}
                />
            </Field>
        </Modal>
    );
};
