import { debounce } from '@astral/utils/debounce';
import { useCallback, useRef, useState } from 'react';
import { useLoadingState } from '../useLoadingState';
/**
 * Хук для асинхронной загрузки опций в компонентах с поиском.
 * Управляет задержкой, отменой запросов и состояниями загрузки.
 */
export const useAsyncOptions = ({ fetchOptions, fetchDelayMs, minSymbolsToFetch, onDataLoadError, isSmoothLoading, }) => {
    const [isLoadingData, setIsLoadingData] = useState(false);
    const [isFirstOpen, setIsFirstOpen] = useState(true);
    const [isLoadingError, setIsLoadingError] = useState(false);
    const abortControllerRef = useRef(null);
    const { isShowLoader } = useLoadingState(isLoadingData);
    const [options, setOptions] = useState({
        options: [],
    });
    const optionsAdapter = useCallback((response) => {
        return Array.isArray(response) ? { options: response } : response;
    }, []);
    const debouncedFetchOptions = useCallback(debounce((search) => {
        abortControllerRef.current?.abort();
        const controller = new AbortController();
        abortControllerRef.current = controller;
        setIsLoadingError(false);
        fetchOptions(search, controller?.signal)
            .then((response) => {
            const normalizeResponse = optionsAdapter(response);
            setOptions(normalizeResponse);
        })
            .catch((error) => {
            // CanceledError название ошибки в axios для отмены запроса
            if (error.name !== 'AbortError' && error.name !== 'CanceledError') {
                setIsLoadingError(true);
                onDataLoadError?.(error);
            }
        })
            .finally(() => {
            setIsLoadingData(false);
            abortControllerRef.current = null;
        });
    }, fetchDelayMs), [fetchOptions, fetchDelayMs]);
    const onInputChange = (search, reason) => {
        if ((!search.length && minSymbolsToFetch > 0) ||
            search.length < minSymbolsToFetch) {
            if (debouncedFetchOptions.isPending) {
                debouncedFetchOptions.clear();
            }
            setIsLoadingData(false);
            setOptions({ options: [] });
            return;
        }
        if (!isFirstOpen) {
            if (reason === 'input') {
                setIsLoadingData(true);
            }
            debouncedFetchOptions(search);
        }
    };
    const onOpen = (defaultSearch = '', defaultValue, isAlwaysTriggerOnOpen = false) => {
        if (isFirstOpen || isAlwaysTriggerOnOpen) {
            setIsFirstOpen(false);
            if (defaultValue || minSymbolsToFetch === 0) {
                setIsLoadingData(true);
                debouncedFetchOptions(defaultSearch);
            }
        }
    };
    const onRetry = (search) => {
        if (debouncedFetchOptions.isPending) {
            debouncedFetchOptions.clear();
        }
        setIsLoadingData(true);
        debouncedFetchOptions(search);
    };
    return {
        options: options.options,
        meta: options.meta,
        isLoadingData: isSmoothLoading ? isShowLoader : isLoadingData,
        onRetry,
        isLoadingError,
        debouncedFetchOptions,
        onInputChange,
        onOpen,
    };
};
