"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { Button } from "../../primitives/button.js";
function normalizeOptions(input) {
  if (!Array.isArray(input)) return [];
  return input.map((option) => {
    if (typeof option === "string") {
      const trimmed = option.trim();
      if (!trimmed) return null;
      return { value: trimmed, label: trimmed };
    }
    const value = typeof option.value === "string" ? option.value.trim() : "";
    if (!value) return null;
    return {
      value,
      label: option.label?.trim() || value,
      description: option.description ?? null
    };
  }).filter((option) => !!option);
}
function ComboboxInput({
  value,
  onChange,
  placeholder,
  suggestions,
  loadSuggestions,
  resolveLabel,
  resolveDescription,
  autoFocus,
  disabled = false,
  allowCustomValues = true
}) {
  const [input, setInput] = React.useState("");
  const [asyncOptions, setAsyncOptions] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [touched, setTouched] = React.useState(false);
  const [showSuggestions, setShowSuggestions] = React.useState(false);
  const [selectedIndex, setSelectedIndex] = React.useState(-1);
  const inputRef = React.useRef(null);
  const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions]);
  const optionMap = React.useMemo(() => {
    const map = /* @__PURE__ */ new Map();
    const register = (option) => {
      if (!map.has(option.value)) {
        map.set(option.value, option);
      }
    };
    staticOptions.forEach(register);
    asyncOptions.forEach(register);
    if (value) {
      const existing = map.get(value);
      if (!existing) {
        map.set(value, {
          value,
          label: resolveLabel?.(value) ?? value,
          description: resolveDescription?.(value) ?? null
        });
      }
    }
    return map;
  }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value]);
  const availableOptions = React.useMemo(() => {
    return Array.from(optionMap.values());
  }, [optionMap]);
  const filteredSuggestions = React.useMemo(() => {
    const query = input.toLowerCase().trim();
    if (!query) return availableOptions;
    return availableOptions.filter((option) => {
      const labelMatch = option.label.toLowerCase().includes(query);
      const descMatch = option.description?.toLowerCase().includes(query);
      return labelMatch || Boolean(descMatch);
    });
  }, [availableOptions, input]);
  React.useEffect(() => {
    if (!loadSuggestions || !touched || disabled) return;
    const query = input.trim();
    let cancelled = false;
    const handle = window.setTimeout(async () => {
      setLoading(true);
      try {
        const items = await loadSuggestions(query);
        if (!cancelled) {
          setAsyncOptions(normalizeOptions(items));
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    }, 200);
    return () => {
      cancelled = true;
      window.clearTimeout(handle);
    };
  }, [disabled, input, loadSuggestions, touched]);
  React.useEffect(() => {
    if (document.activeElement !== inputRef.current) {
      const option = optionMap.get(value);
      setInput(option?.label ?? value ?? "");
    }
  }, [value, optionMap]);
  const selectValue = React.useCallback(
    (nextValue) => {
      if (disabled) return;
      const trimmed = nextValue.trim();
      onChange(trimmed);
      const option = optionMap.get(trimmed);
      setInput(option?.label ?? trimmed);
      setShowSuggestions(false);
      setSelectedIndex(-1);
    },
    [disabled, onChange, optionMap]
  );
  const findOptionForInput = React.useCallback(
    (raw) => {
      const query = raw.trim().toLowerCase();
      if (!query) return null;
      for (const option of optionMap.values()) {
        if (option.value === raw.trim()) return option;
        if (option.label.toLowerCase() === query) return option;
      }
      return null;
    },
    [optionMap]
  );
  const confirmSelection = React.useCallback(
    (raw) => {
      if (disabled) return;
      const option = findOptionForInput(raw);
      if (option) {
        selectValue(option.value);
        return;
      }
      if (!allowCustomValues) {
        const currentOption = optionMap.get(value);
        setInput(currentOption?.label ?? value ?? "");
        setShowSuggestions(false);
        return;
      }
      selectValue(raw);
    },
    [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]
  );
  const handleKeyDown = React.useCallback(
    (event) => {
      if (disabled) return;
      if (event.key === "ArrowDown") {
        event.preventDefault();
        if (!showSuggestions) {
          setShowSuggestions(true);
          setSelectedIndex(0);
        } else {
          setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1));
        }
      } else if (event.key === "ArrowUp") {
        event.preventDefault();
        setSelectedIndex((prev) => Math.max(prev - 1, -1));
      } else if (event.key === "Enter") {
        event.preventDefault();
        if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {
          selectValue(filteredSuggestions[selectedIndex].value);
        } else {
          confirmSelection(input);
        }
      } else if (event.key === "Escape") {
        event.preventDefault();
        setShowSuggestions(false);
        setSelectedIndex(-1);
      }
    },
    [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]
  );
  return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
    /* @__PURE__ */ jsx(
      "input",
      {
        ref: inputRef,
        type: "text",
        className: "w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
        value: input,
        placeholder: placeholder || "Type to search...",
        autoFocus,
        "data-crud-focus-target": "",
        disabled,
        onFocus: () => {
          setTouched(true);
          setShowSuggestions(true);
        },
        onChange: (event) => {
          setTouched(true);
          setInput(event.target.value);
          setShowSuggestions(true);
          setSelectedIndex(-1);
        },
        onKeyDown: handleKeyDown,
        onBlur: () => {
          setTimeout(() => {
            if (disabled) return;
            confirmSelection(input);
          }, 200);
        }
      }
    ),
    showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && /* @__PURE__ */ jsx("div", { className: "absolute z-50 w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto", children: loading && touched ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: "Loading suggestions\u2026" }) : filteredSuggestions.map((option, index) => /* @__PURE__ */ jsxs(
      Button,
      {
        type: "button",
        variant: "ghost",
        size: "sm",
        className: [
          "w-full h-auto justify-start font-normal text-left flex flex-col items-start px-3 py-2",
          index === selectedIndex ? "bg-accent" : ""
        ].filter(Boolean).join(" "),
        onMouseDown: (event) => event.preventDefault(),
        onClick: () => selectValue(option.value),
        onMouseEnter: () => setSelectedIndex(index),
        children: [
          /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label }),
          option.description ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: option.description }) : null
        ]
      },
      option.value
    )) })
  ] });
}
export {
  ComboboxInput
};
//# sourceMappingURL=ComboboxInput.js.map
