import { jsxs, jsx } from 'react/jsx-runtime';
import { useId, useMemo, useState, useCallback, useRef, forwardRef } from 'react';
import { c as cn } from './utils-BJnb9o5c.js';
import { Popover, PopoverTrigger, PopoverContent } from './primitives/Popover.js';
import { S as SelectFieldWrapper } from './SelectFieldWrapper-CiBARDsn.js';
import { f as findNode, w as walkTree, T as Tree } from './Tree-BlzjThRi.js';
import { X } from './x-_o2T3n6D.js';
import { C as ChevronDown } from './chevron-down-BNi0ntys.js';

const pruneTree = (nodes, searchTerm) => {
  if (!searchTerm.trim()) return nodes;
  const lower = searchTerm.toLowerCase();
  const prune = (items) => items.reduce((acc, node) => {
    const titleStr = typeof node.title === "string" ? node.title : "";
    const nodeMatches = titleStr.toLowerCase().includes(lower);
    if (nodeMatches) {
      acc.push(node);
    } else {
      const prunedChildren = node.children ? prune(node.children) : [];
      if (prunedChildren.length > 0) {
        acc.push({ ...node, children: prunedChildren });
      }
    }
    return acc;
  }, []);
  return prune(nodes);
};

const resolveFieldNames = (nodes, fieldNames) => {
  const labelKey = fieldNames.label ?? "title";
  const valueKey = fieldNames.value ?? "key";
  const remap = (items) => items.map((item) => {
    const record = item;
    return {
      key: String(record[valueKey] ?? ""),
      title: record[labelKey],
      disabled: record.disabled,
      children: Array.isArray(item.children) ? remap(item.children) : void 0
    };
  });
  return remap(nodes);
};

function useTreeSelectValue(props) {
  const {
    value: valueProp,
    defaultValue,
    onChange,
    treeData: rawTreeData,
    fieldNames,
    isClearable = false,
    isDisabled = false,
    size = "medium",
    label = "",
    error = "",
    helpText = "",
    required = false
  } = props;
  const id = useId();
  const errorId = `error_${id}`;
  const helpTextId = `helpText_${id}`;
  const treeData = useMemo(() => {
    if (!fieldNames) return rawTreeData;
    return resolveFieldNames(rawTreeData, fieldNames);
  }, [rawTreeData, fieldNames?.label, fieldNames?.value]);
  const isControlled = valueProp !== void 0;
  const [internalValue, setInternalValue] = useState(defaultValue ?? "");
  const currentValue = isControlled ? valueProp ?? "" : internalValue;
  const applyValue = useCallback(
    (next) => {
      if (!isControlled) setInternalValue(next);
      onChange?.(next);
    },
    [isControlled, onChange]
  );
  const selectedLabel = useMemo(() => {
    if (!currentValue) return "";
    const node = findNode(currentValue, treeData);
    if (!node) return currentValue;
    return typeof node.title === "string" ? node.title : "";
  }, [currentValue, treeData]);
  const handleClear = useCallback(
    (e) => {
      e.stopPropagation();
      applyValue("");
    },
    [applyValue]
  );
  const showClearButton = isClearable && !!currentValue && !isDisabled;
  return {
    id,
    errorId,
    helpTextId,
    label,
    error,
    helpText,
    required,
    isDisabled,
    size,
    treeData,
    currentValue,
    selectedLabel,
    applyValue,
    handleClear,
    showClearButton
  };
}

function useTreeSelectState(props) {
  const { isSearchable = false, defaultExpandedKeys } = props;
  const defaultExpandedKeysRef = useRef(defaultExpandedKeys);
  defaultExpandedKeysRef.current = defaultExpandedKeys;
  const value = useTreeSelectValue(props);
  const [isOpen, setIsOpen] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");
  const [expandedKeys, setExpandedKeys] = useState(
    defaultExpandedKeys ?? []
  );
  const prunedTreeData = useMemo(
    () => searchTerm.trim() ? pruneTree(value.treeData, searchTerm) : value.treeData,
    [value.treeData, searchTerm]
  );
  const effectiveExpandedKeys = useMemo(() => {
    if (!searchTerm) return expandedKeys;
    const allKeys = [];
    walkTree(prunedTreeData, (node) => {
      if (node.children?.length) allKeys.push(node.key);
    });
    return allKeys;
  }, [searchTerm, prunedTreeData]);
  const handleSelect = useCallback(
    (keys, info) => {
      if (value.isDisabled || info.node.disabled) return;
      value.applyValue(keys[0] ?? "");
      setIsOpen(false);
      setSearchTerm("");
    },
    [value.applyValue, value.isDisabled]
  );
  const handleOpenChange = useCallback(
    (open) => {
      if (value.isDisabled) return;
      setIsOpen(open);
      if (!open) {
        setSearchTerm("");
        setExpandedKeys(defaultExpandedKeysRef.current ?? []);
      }
    },
    [value.isDisabled]
  );
  const handleExpand = useCallback(
    (keys) => setExpandedKeys(keys),
    []
  );
  return {
    ...value,
    isSearchable,
    isOpen,
    handleOpenChange,
    searchTerm,
    setSearchTerm,
    prunedTreeData,
    effectiveExpandedKeys,
    handleSelect,
    handleExpand
  };
}

const DROPDOWN_HEIGHT = 256;
const SIZE_CONFIG = {
  small: { trigger: "min-h-7 px-2 py-0.5", text: "text-xs" },
  medium: { trigger: "min-h-8 px-2.5 py-1", text: "text-sm" },
  large: { trigger: "min-h-10 px-2.5 py-1.5", text: "text-sm" }
};

const TreeSelectTrigger = forwardRef(
  ({
    size,
    currentValue,
    selectedLabel,
    placeholder,
    isDisabled,
    error,
    showClearButton,
    handleClear,
    suffixIcon,
    className,
    ...rest
  }, ref) => /* @__PURE__ */ jsxs(
    "button",
    {
      ref,
      type: "button",
      disabled: isDisabled,
      ...rest,
      className: cn(
        "inline-flex w-full items-center gap-1 rounded-md border border-input bg-background outline-none",
        "hover:bg-accent focus:ring-1 focus:ring-ring",
        "disabled:pointer-events-none disabled:opacity-50",
        error && "border-destructive",
        SIZE_CONFIG[size].trigger,
        SIZE_CONFIG[size].text,
        className
      ),
      children: [
        /* @__PURE__ */ jsx(
          "span",
          {
            className: cn(
              "flex-1 truncate text-left",
              !currentValue && "text-muted-foreground"
            ),
            children: selectedLabel || placeholder || ""
          }
        ),
        showClearButton && /* @__PURE__ */ jsx(
          "span",
          {
            role: "button",
            tabIndex: -1,
            "aria-label": "Clear selection",
            className: "shrink-0 text-muted-foreground hover:text-foreground",
            onClick: handleClear,
            children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
          }
        ),
        suffixIcon ?? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 opacity-50" })
      ]
    }
  )
);
TreeSelectTrigger.displayName = "TreeSelectTrigger";

const TreeSelect = forwardRef(
  (props, ref) => {
    const {
      id,
      label,
      error,
      helpText,
      errorId,
      helpTextId,
      isDisabled,
      required,
      isOpen,
      handleOpenChange,
      currentValue,
      handleClear,
      selectedLabel,
      showClearButton,
      size,
      isSearchable,
      searchTerm,
      setSearchTerm,
      prunedTreeData,
      effectiveExpandedKeys,
      handleSelect,
      handleExpand
    } = useTreeSelectState(props);
    const { suffixIcon, switcherIcon, autoExpandParent, className } = props;
    return /* @__PURE__ */ jsx(
      SelectFieldWrapper,
      {
        id,
        label,
        error,
        helpText,
        errorId,
        helpTextId,
        isDisabled,
        required,
        className,
        children: /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: handleOpenChange, children: [
          /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
            TreeSelectTrigger,
            {
              ref,
              currentValue,
              error,
              handleClear,
              isDisabled,
              placeholder: props.placeholder,
              selectedLabel,
              showClearButton,
              size,
              suffixIcon
            }
          ) }),
          /* @__PURE__ */ jsxs(
            PopoverContent,
            {
              align: "start",
              className: "w-[var(--radix-popover-trigger-width)] p-0",
              onOpenAutoFocus: (e) => {
                if (isSearchable) e.preventDefault();
              },
              children: [
                isSearchable && /* @__PURE__ */ jsx("div", { className: "border-b border-border px-2 py-1.5", children: /* @__PURE__ */ jsx(
                  "input",
                  {
                    autoFocus: true,
                    type: "text",
                    className: cn(
                      "w-full bg-transparent outline-none placeholder:text-muted-foreground",
                      SIZE_CONFIG[size].text
                    ),
                    placeholder: "Search...",
                    value: searchTerm,
                    onChange: (e) => setSearchTerm(e.target.value)
                  }
                ) }),
                prunedTreeData.length > 0 ? /* @__PURE__ */ jsx("div", { className: "p-1", children: /* @__PURE__ */ jsx(
                  Tree,
                  {
                    autoExpandParent,
                    expandedKeys: effectiveExpandedKeys,
                    height: DROPDOWN_HEIGHT,
                    switcherIcon,
                    treeData: prunedTreeData,
                    onExpand: handleExpand,
                    onSelect: handleSelect
                  }
                ) }) : /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-sm text-muted-foreground", children: "No results found." })
              ]
            }
          )
        ] })
      }
    );
  }
);
TreeSelect.displayName = "TreeSelect";

export { TreeSelect as T };
//# sourceMappingURL=TreeSelect-Dk299XMv.js.map
