import { useState, useRef, useEffect, useCallback, useMemo } from 'react';

/**
 * useSelectState
 *
 * A headless hook that manages all state for select/dropdown components.
 * This hook can be used by Select, Combobox, MultiSelect, TagInput, etc.
 *
 * @example
 * ```tsx
 * const selectState = useSelectState({
 *   options,
 *   value,
 *   onChange,
 *   searchable: true,
 * });
 *
 * // Use in your component:
 * const { isOpen, setIsOpen, filteredOptions, selectOption } = selectState;
 * ```
 */
function useSelectState({ options = [], value, onChange, searchable = false, creatable = false, onCreateOption, createLabel, enableTypeahead = true, multiple = false, }) {
    // Core state
    const [isOpen, setIsOpen] = useState(false);
    const [selectedValue, setSelectedValue] = useState(value);
    const [highlightedIndex, setHighlightedIndex] = useState(-1);
    const [searchValue, setSearchValue] = useState("");
    // Multi-select state
    const [selectedValues, setSelectedValues] = useState(() => {
        if (multiple && Array.isArray(value))
            return value;
        return [];
    });
    // Typeahead state
    const [typeaheadValue, setTypeaheadValue] = useState("");
    const typeaheadTimeoutRef = useRef(null);
    // Refs for trigger and options container
    const triggerRef = useRef(null);
    const optionsRef = useRef(null);
    // Sync internal state with controlled value
    useEffect(() => {
        if (multiple && Array.isArray(value)) {
            setSelectedValues(value);
        }
        else {
            setSelectedValue(value);
        }
    }, [value, multiple]);
    // Get option by value
    const getOptionByValue = useCallback((searchVal) => {
        return options.find((option) => option.value === searchVal);
    }, [options]);
    // Selected option derived from selectedValue
    const selectedOption = useMemo(() => {
        return selectedValue !== undefined
            ? getOptionByValue(selectedValue)
            : undefined;
    }, [selectedValue, getOptionByValue]);
    // Filter options based on search query
    const baseFilteredOptions = useMemo(() => {
        if (!searchValue)
            return options;
        return options.filter((option) => option.label.toLowerCase().includes(searchValue.toLowerCase()));
    }, [options, searchValue]);
    // Check if we should show the create option
    const hasCreateOption = useMemo(() => {
        return (creatable &&
            searchable &&
            searchValue.trim() !== "" &&
            !baseFilteredOptions.some((option) => option.label.toLowerCase() === searchValue.toLowerCase()));
    }, [creatable, searchable, searchValue, baseFilteredOptions]);
    // Final filtered options with create option if applicable
    const filteredOptions = useMemo(() => {
        if (!hasCreateOption)
            return baseFilteredOptions;
        const createOptionLabel = typeof createLabel === "function"
            ? createLabel(searchValue)
            : createLabel || `Create "${searchValue}"`;
        return [
            {
                id: "__create__",
                label: createOptionLabel,
                value: searchValue,
            },
            ...baseFilteredOptions,
        ];
    }, [hasCreateOption, baseFilteredOptions, searchValue, createLabel]);
    // Multi-select helpers
    const isValueSelected = useCallback((val) => {
        return selectedValues.some((v) => v === val);
    }, [selectedValues]);
    const removeValue = useCallback((val) => {
        const updated = selectedValues.filter((v) => v !== val);
        setSelectedValues(updated);
        onChange === null || onChange === void 0 ? void 0 : onChange(updated);
    }, [selectedValues, onChange]);
    // Select an option
    const selectOption = useCallback((newValue, isCreateAction = false) => {
        // Handle create action callback
        if (isCreateAction && onCreateOption) {
            onCreateOption(String(newValue));
        }
        if (multiple) {
            // Toggle value in multi-select mode
            const isAlreadySelected = selectedValues.some((v) => v === newValue);
            const updated = isAlreadySelected
                ? selectedValues.filter((v) => v !== newValue)
                : [...selectedValues, newValue];
            setSelectedValues(updated);
            onChange === null || onChange === void 0 ? void 0 : onChange(updated);
            // Don't close dropdown in multi-select mode
            setSearchValue("");
            return;
        }
        // Single-select: update state if value changed
        if (newValue !== selectedValue) {
            setSelectedValue(newValue);
            onChange === null || onChange === void 0 ? void 0 : onChange(newValue);
        }
        // Close and reset
        setIsOpen(false);
        setSearchValue("");
    }, [selectedValue, selectedValues, onChange, onCreateOption, multiple]);
    // Reset state when closing
    useEffect(() => {
        if (!isOpen) {
            setSearchValue("");
            setHighlightedIndex(-1);
            setTypeaheadValue("");
            // Clear any pending typeahead timeout
            if (typeaheadTimeoutRef.current) {
                clearTimeout(typeaheadTimeoutRef.current);
                typeaheadTimeoutRef.current = null;
            }
        }
    }, [isOpen]);
    return {
        // Core state
        isOpen,
        setIsOpen,
        highlightedIndex,
        setHighlightedIndex,
        searchValue,
        setSearchValue,
        selectedValue,
        setSelectedValue,
        // Typeahead state
        typeaheadValue,
        setTypeaheadValue,
        typeaheadTimeoutRef,
        // Derived state
        filteredOptions,
        selectedOption,
        hasCreateOption,
        // Actions
        selectOption,
        getOptionByValue,
        // Multi-select state
        multiple,
        selectedValues,
        isValueSelected,
        removeValue,
        // Refs
        triggerRef,
        optionsRef,
        // Original options
        options,
    };
}

export { useSelectState };
