import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Field, Form, Select } from '@theorchard/suite-components';
import { LabelType } from 'src/apollo/definitions/globalTypes';
import {
    useVendorSearch,
    useVendorById,
} from 'src/apollo/queries/vendor-search';
import type { AbacusContractTermsInputErrors } from 'src/types/abacus-contract-terms-distro-input-errors';
import type { VendorSearchItem } from 'src/types/abacus-vendor';

export interface VendorSearchProps {
    // eslint-disable-next-line no-unused-vars
    onChange: (vendor?: VendorSearchItem) => void;
    initialVendorId?: number;
    errors: AbacusContractTermsInputErrors;
    setErrors: React.Dispatch<
        React.SetStateAction<AbacusContractTermsInputErrors>
    >;
}

interface VendorOption {
    label: string;
    value: string;
    raw: VendorSearchItem;
}

interface SearchResponse {
    data: VendorOption[];
}

export const VendorSearch: React.FC<VendorSearchProps> = ({
    onChange,
    initialVendorId,
    errors,
    setErrors,
}) => {
    const toOption = useCallback(
        (item: VendorSearchItem): VendorOption => ({
            label: item.name,
            value: item.id.vendorId.toString(),
            raw: item,
        }),
        []
    );

    const [selectedOption, setSelectedOption] = useState<VendorOption>();
    const [fetchedInitial, setFetchedInitial] = useState(false);

    const getVendorByIdObj = useVendorById();
    const getVendorByIdRef = useRef(getVendorByIdObj.getVendorById);

    // eslint-disable-next-line react-hooks/exhaustive-deps
    const memoizedOnChange = useCallback(onChange, []);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    const memoizedSetErrors = useCallback(setErrors, []);

    useEffect(() => {
        if (!initialVendorId || fetchedInitial) return;

        const fetchVendor = async () => {
            try {
                const result = await getVendorByIdRef.current(initialVendorId);
                const fetched = result?.data?.orchardLabel;

                if (fetched?.id?.vendorId === initialVendorId && fetched.name) {
                    const vendorItem: VendorSearchItem = {
                        id: { vendorId: fetched.id.vendorId },
                        name: fetched.name,
                    };
                    const option = toOption(vendorItem);
                    setSelectedOption(option);
                    memoizedOnChange(vendorItem);
                } else {
                    setSelectedOption(undefined);
                    memoizedOnChange(undefined);
                }

                setFetchedInitial(true);
            } catch (err) {
                console.error('Failed to fetch vendor by ID:', err);
                const message = `Error loading vendor: ${
                    err instanceof Error ? err.message : 'Unknown error'
                }`;
                memoizedSetErrors(prev => ({ ...prev, vendor: message }));
                setFetchedInitial(true);
            }
        };

        void fetchVendor();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [initialVendorId, fetchedInitial]);

    const getVendor = useVendorSearch();
    const DEFAULT_LIMIT = 100;
    const DEFAULT_OFFSET = 0;
    const BACKSLASH_REGEX = /\\/g;

    const sanitizeTerm = (term: string) =>
        term.trim().replace(BACKSLASH_REGEX, '');

    const performSearch = async (term = ''): Promise<SearchResponse> => {
        setErrors(prev => {
            const { ['vendor']: _, ...rest } = prev;
            return rest;
        });
        const query = sanitizeTerm(term);
        if (!query) return { data: [] };

        try {
            const rawItems = await getVendor(
                query,
                LabelType.VENDOR,
                DEFAULT_LIMIT,
                DEFAULT_OFFSET
            );
            return { data: rawItems.map(toOption) };
        } catch (err) {
            console.error(`Vendor search failed for "${term}":`, err);
            const message = `${err instanceof Error ? 'Account Search failed (Retry)' : 'Unknown error'}`;
            setErrors(prev => ({ ...prev, vendor: message }));
            return { data: [] };
        }
    };

    const handleChange = (option?: VendorOption) => {
        setSelectedOption(option);
        onChange(option?.raw);
    };

    return (
        <Form.Group className="ContractTermsDistroFormFields-VendorSearch">
            <Field
                controlId="VendorSelect"
                labelText="Account"
                isOptional={true}
                testId="contract-term-distro-vendor-select"
                message={
                    errors?.vendor
                        ? { type: 'error', text: errors.vendor }
                        : undefined
                }
            >
                <Select<VendorOption>
                    key={selectedOption?.value ?? ''}
                    placeholder="Search for Account"
                    onChange={handleChange}
                    onClear={handleChange}
                    onLoadOptions={performSearch}
                    selectedValue={selectedOption?.label}
                    menuWidth="100%"
                    data-testid="vendor-search-select"
                />
            </Field>
        </Form.Group>
    );
};
