import {
  useComboboxHighlight
} from "./chunk-XZUQV54A.js";
import {
  useComboboxOptions
} from "./chunk-GU5OMKTM.js";
import {
  Listbox
} from "./chunk-PQSPISME.js";
import {
  getOptionLabel,
  getOptionValue,
  isOptionGroup
} from "./chunk-2JLZNSLY.js";
import {
  TextField
} from "./chunk-6RDK3FM2.js";
import {
  VisuallyHidden
} from "./chunk-PRZRE6A5.js";
import {
  useBreakpoint
} from "./chunk-7FQ7SXK4.js";

// src/components/Combobox/Combobox.tsx
import { useOnUnmount } from "@simplybusiness/mobius-hooks";
import classNames from "classnames/dedupe";
import { useEffect, useId, useRef, useState } from "react";
import "@simplybusiness/mobius/src/components/Combobox/Combobox.css";
import { jsx, jsxs } from "react/jsx-runtime";
var ComboboxInner = ({
  ref,
  ...props
}) => {
  const {
    id,
    defaultValue,
    value,
    options,
    asyncOptions,
    delay,
    minSearchLength,
    onSelected,
    className,
    placeholder,
    icon,
    onBlur,
    onFocus,
    onChange,
    // onSearched, // unused prop, consider removing
    optionComponent,
    optionTestIdPrefix,
    errorMessage,
    ...otherProps
  } = props;
  const skipNextDebounceRef = useRef(false);
  const fallbackRef = useRef(null);
  const [inputValue, setInputValue] = useState(defaultValue || "");
  const [isOpen, setIsOpen] = useState(false);
  const [isChanging, setIsChanging] = useState(false);
  const { filteredOptions, updateFilteredOptions, isLoading, error } = useComboboxOptions({
    options,
    asyncOptions,
    inputValue,
    delay,
    minSearchLength,
    skipNextDebounceRef
  });
  const [validationError, setValidationError] = useState(
    error?.message || errorMessage
  );
  const {
    highlightedIndex,
    highlightedGroupIndex,
    highlightNextOption,
    highlightPreviousOption,
    highlightFirstOption,
    highlightLastOption,
    clearHighlight
  } = useComboboxHighlight(filteredOptions);
  const inputRef = ref || fallbackRef;
  const listboxId = useId();
  const statusId = useId();
  const blurTimeoutRef = useRef(null);
  const userInteractedRef = useRef(false);
  const justSelectedRef = useRef(false);
  const { down } = useBreakpoint();
  const isMobile = down("md");
  useEffect(() => {
    setValidationError(error?.message || errorMessage);
  }, [error, errorMessage]);
  const getEmptyValue = () => {
    const firstOption = filteredOptions ? isOptionGroup(filteredOptions) ? filteredOptions[0]?.options[0] : filteredOptions[0] : options ? isOptionGroup(options) ? options[0]?.options[0] : options[0] : void 0;
    if (typeof firstOption === "string") {
      return "";
    }
    return { label: "", value: "" };
  };
  const handleFocus = (e) => {
    onFocus?.(e);
    if (!filteredOptions || filteredOptions.length === 0) return;
    if (blurTimeoutRef.current) {
      clearTimeout(blurTimeoutRef.current);
      blurTimeoutRef.current = null;
    }
    const isNaturalFocus = userInteractedRef.current || e.relatedTarget !== null;
    if (userInteractedRef.current) {
      userInteractedRef.current = false;
    }
    if (justSelectedRef.current && !isNaturalFocus) {
      return;
    }
    if (isNaturalFocus) {
      setIsOpen(true);
      justSelectedRef.current = false;
    }
  };
  useEffect(() => {
    if (!inputRef || typeof inputRef === "function") return;
    const inputElement = inputRef.current;
    if (!inputElement) return;
    const handleMouseDown = () => {
      userInteractedRef.current = true;
    };
    inputElement.addEventListener("mousedown", handleMouseDown);
    return () => {
      inputElement.removeEventListener("mousedown", handleMouseDown);
    };
  }, [inputRef]);
  useOnUnmount(() => {
    if (blurTimeoutRef.current) {
      clearTimeout(blurTimeoutRef.current);
    }
  });
  const handleInputChange = (e) => {
    const newValue = e.target.value;
    setInputValue(newValue);
    setValidationError(void 0);
    justSelectedRef.current = false;
    setIsChanging(true);
    if (!asyncOptions) {
      setIsOpen(true);
    }
    clearHighlight();
    onChange?.(e);
  };
  const handleOptionSelect = (option) => {
    const val = getOptionValue(option);
    if (!val && val !== "") return;
    if (typeof option === "object" && "callback" in option && option.callback && typeof option.callback === "function") {
      justSelectedRef.current = true;
      setTimeout(() => {
        if (inputRef && typeof inputRef !== "function" && inputRef.current) {
          inputRef.current.focus();
        }
      }, 0);
      const callbackPromise = option.callback();
      updateFilteredOptions(callbackPromise);
      callbackPromise.then(() => {
        setIsOpen(true);
        setIsChanging(true);
      }).catch(() => {
      });
      return;
    }
    skipNextDebounceRef.current = true;
    justSelectedRef.current = true;
    setIsChanging(false);
    setValidationError(void 0);
    setIsOpen(false);
    setInputValue(val);
    onSelected?.(option);
  };
  const getFirstOption = () => {
    if (!filteredOptions) return void 0;
    if (isOptionGroup(filteredOptions)) {
      return filteredOptions[0]?.options[0];
    }
    return filteredOptions[0];
  };
  const getHighlightedOption = () => {
    if (!filteredOptions) return void 0;
    if (highlightedIndex === -1) return void 0;
    if (isOptionGroup(filteredOptions)) {
      const group = filteredOptions[highlightedGroupIndex];
      return group?.options[highlightedIndex];
    }
    return filteredOptions[highlightedIndex];
  };
  const getHighlightedOptionId = () => {
    const option = getHighlightedOption();
    if (!option) return void 0;
    if (isOptionGroup(filteredOptions)) {
      return `${listboxId}-option-${highlightedGroupIndex}-${highlightedIndex}`;
    }
    return `${listboxId}-option-${highlightedIndex}`;
  };
  const handleBlur = (e) => {
    if (!justSelectedRef.current) {
      const typedText = inputValue.trim();
      const typedTextLower = typedText.toLowerCase();
      const highlightedOption = getHighlightedOption();
      const label = getOptionLabel(highlightedOption);
      if (typedTextLower === label?.toLowerCase()) {
        setTimeout(() => {
          handleOptionSelect(highlightedOption);
        }, 0);
      } else if (typedText === "") {
        setTimeout(() => {
          handleOptionSelect(getEmptyValue());
        }, 0);
      } else {
        setValidationError(
          errorMessage || "Please select an option from the list"
        );
        setTimeout(() => {
          setInputValue("");
        }, 0);
      }
    }
    blurTimeoutRef.current = setTimeout(() => {
      onBlur?.(e);
      setIsOpen(false);
      setIsChanging(false);
    }, 150);
  };
  const handleKeyDown = (e) => {
    switch (e.key) {
      case "ArrowDown":
        e.preventDefault();
        justSelectedRef.current = false;
        setIsOpen(true);
        highlightNextOption();
        break;
      case "ArrowUp":
        e.preventDefault();
        justSelectedRef.current = false;
        setIsOpen(true);
        highlightPreviousOption();
        break;
      case "Home":
        e.preventDefault();
        justSelectedRef.current = false;
        setIsOpen(true);
        highlightFirstOption();
        break;
      case "End":
        e.preventDefault();
        justSelectedRef.current = false;
        setIsOpen(true);
        highlightLastOption();
        break;
      case "Enter":
        e.preventDefault();
        if (isOpen) {
          const selectedOption = getHighlightedOption() || getFirstOption();
          if (selectedOption) {
            handleOptionSelect(selectedOption);
          }
        }
        break;
      case "Escape":
        e.preventDefault();
        setInputValue("");
        setIsOpen(false);
        clearHighlight();
        break;
      default:
    }
  };
  useEffect(() => {
    if (value) {
      setInputValue(value);
    }
  }, [value]);
  useEffect(() => {
    if (asyncOptions && isChanging) {
      setIsOpen(!!filteredOptions && filteredOptions.length > 0);
    }
  }, [filteredOptions, asyncOptions, isChanging]);
  const classes = classNames(
    "mobius mobius-combobox",
    {
      "mobius-combobox--is-expanded": isOpen,
      "mobius-combobox--is-loading": isLoading,
      "mobius-combobox--is-mobile": isMobile
    },
    className
  );
  const getStatusMessage = () => {
    if (isLoading) return "Loading options";
    if (!filteredOptions || filteredOptions.length === 0) {
      return isChanging ? "No options found" : "";
    }
    const count = isOptionGroup(filteredOptions) ? filteredOptions.reduce((sum, group) => sum + group.options.length, 0) : filteredOptions.length;
    return isOpen && isChanging ? `${count} option${count === 1 ? "" : "s"} available` : "";
  };
  return /* @__PURE__ */ jsxs("div", { id, "data-testid": "mobius-combobox__wrapper", className: classes, children: [
    /* @__PURE__ */ jsx(
      VisuallyHidden,
      {
        role: "status",
        "aria-live": "polite",
        id: statusId,
        elementType: "div",
        className: "mobius-combobox__status",
        children: getStatusMessage()
      }
    ),
    /* @__PURE__ */ jsx(
      TextField,
      {
        ...otherProps,
        className: "mobius-combobox__input",
        role: "combobox",
        value: inputValue,
        placeholder,
        onFocus: handleFocus,
        onBlur: handleBlur,
        onKeyDown: handleKeyDown,
        onChange: handleInputChange,
        autoComplete: "off",
        "aria-describedby": isLoading ? statusId : void 0,
        "aria-autocomplete": "list",
        "aria-haspopup": "listbox",
        "aria-controls": isOpen ? listboxId : void 0,
        "aria-expanded": isOpen,
        "aria-activedescendant": highlightedIndex === -1 ? void 0 : getHighlightedOptionId(),
        prefixInside: icon,
        ref: inputRef,
        errorMessage: errorMessage || validationError || error?.message
      }
    ),
    /* @__PURE__ */ jsx(
      Listbox,
      {
        id: listboxId,
        isOpen,
        isLoading,
        options: filteredOptions,
        highlightedIndex,
        highlightedGroupIndex,
        onOptionSelect: handleOptionSelect,
        optionComponent,
        optionTestIdPrefix
      }
    )
  ] });
};
var Combobox = ComboboxInner;

export {
  Combobox
};
//# sourceMappingURL=chunk-XEP6X7JU.js.map
