import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import { cx } from '@emotion/css';
import { useVirtualizer } from '@tanstack/react-virtual';
import { useCombobox } from 'downshift';
import { useState, useMemo, useId, useCallback } from 'react';
import '@grafana/data';
import { useStyles2 } from '../../themes/ThemeContext.js';
import 'micro-memoize';
import '@emotion/react';
import 'tinycolor2';
import '../../utils/skeleton.js';
import { t } from '../../utils/i18n.js';
import { Icon } from '../Icon/Icon.js';
import { AutoSizeInput } from '../Input/AutoSizeInput.js';
import { Input } from '../Input/Input.js';
import { getComboboxStyles } from './getComboboxStyles.js';
import { estimateSize, useComboboxFloat } from './useComboboxFloat.js';

function itemToString(item) {
  var _a, _b;
  return (_b = (_a = item == null ? void 0 : item.label) != null ? _a : item == null ? void 0 : item.value.toString()) != null ? _b : "";
}
function itemFilter(inputValue) {
  const lowerCasedInputValue = inputValue.toLowerCase();
  return (item) => {
    var _a, _b;
    return !inputValue || ((_a = item == null ? void 0 : item.label) == null ? void 0 : _a.toLowerCase().includes(lowerCasedInputValue)) || ((_b = item == null ? void 0 : item.value) == null ? void 0 : _b.toString().toLowerCase().includes(lowerCasedInputValue));
  };
}
const Combobox = ({
  options,
  onChange,
  value,
  isClearable = false,
  createCustomValue = false,
  id,
  width,
  "aria-labelledby": ariaLabelledBy,
  ...restProps
}) => {
  const [items, setItems] = useState(options);
  const selectedItemIndex = useMemo(() => {
    if (value === null) {
      return null;
    }
    const index = options.findIndex((option) => option.value === value);
    if (index === -1) {
      return null;
    }
    return index;
  }, [options, value]);
  const selectedItem = useMemo(() => {
    if (selectedItemIndex !== null) {
      return options[selectedItemIndex];
    }
    if (value !== null) {
      return {
        label: value.toString(),
        value
      };
    }
    return null;
  }, [selectedItemIndex, options, value]);
  const menuId = `downshift-${useId().replace(/:/g, "--")}-menu`;
  const labelId = `downshift-${useId().replace(/:/g, "--")}-label`;
  const styles = useStyles2(getComboboxStyles);
  const virtualizerOptions = {
    count: items.length,
    getScrollElement: () => floatingRef.current,
    estimateSize,
    overscan: 4
  };
  const rowVirtualizer = useVirtualizer(virtualizerOptions);
  const {
    getInputProps,
    getMenuProps,
    getItemProps,
    isOpen,
    highlightedIndex,
    setInputValue,
    openMenu,
    closeMenu,
    selectItem
  } = useCombobox({
    menuId,
    labelId,
    inputId: id,
    items,
    itemToString,
    selectedItem,
    onSelectedItemChange: ({ selectedItem: selectedItem2 }) => {
      onChange(selectedItem2);
    },
    defaultHighlightedIndex: selectedItemIndex != null ? selectedItemIndex : 0,
    scrollIntoView: () => {
    },
    onInputValueChange: ({ inputValue }) => {
      const filteredItems = options.filter(itemFilter(inputValue));
      if (createCustomValue && inputValue && filteredItems.findIndex((opt) => opt.label === inputValue) === -1) {
        const customValueOption = {
          label: inputValue,
          // @ts-ignore Type casting needed to make this work when T is a number
          value: inputValue,
          description: t("combobox.custom-value.create", "Create custom value")
        };
        setItems([...filteredItems, customValueOption]);
        return;
      } else {
        setItems(filteredItems);
      }
    },
    onIsOpenChange: ({ isOpen: isOpen2 }) => {
      if (isOpen2) {
        setItems(options);
        return;
      }
    },
    onHighlightedIndexChange: ({ highlightedIndex: highlightedIndex2, type }) => {
      if (type !== useCombobox.stateChangeTypes.MenuMouseLeave) {
        rowVirtualizer.scrollToIndex(highlightedIndex2);
      }
    }
  });
  const { inputRef, floatingRef, floatStyles } = useComboboxFloat(items, rowVirtualizer.range, isOpen);
  const onBlur = useCallback(() => {
    var _a, _b;
    setInputValue((_b = (_a = selectedItem == null ? void 0 : selectedItem.label) != null ? _a : value == null ? void 0 : value.toString()) != null ? _b : "");
  }, [selectedItem, setInputValue, value]);
  const InputComponent = width === "auto" ? AutoSizeInput : Input;
  return /* @__PURE__ */ jsxs("div", { children: [
    /* @__PURE__ */ jsx(
      InputComponent,
      {
        width: width === "auto" ? void 0 : width,
        suffix: /* @__PURE__ */ jsxs(Fragment, { children: [
          !!value && value === (selectedItem == null ? void 0 : selectedItem.value) && isClearable && /* @__PURE__ */ jsx(
            Icon,
            {
              name: "times",
              className: styles.clear,
              title: t("combobox.clear.title", "Clear value"),
              tabIndex: 0,
              role: "button",
              onClick: () => {
                selectItem(null);
              },
              onKeyDown: (e) => {
                if (e.key === "Enter" || e.key === " ") {
                  selectItem(null);
                }
              }
            }
          ),
          /* @__PURE__ */ jsx(
            Icon,
            {
              name: isOpen ? "search" : "angle-down",
              onClick: () => {
                if (isOpen) {
                  closeMenu();
                } else {
                  openMenu();
                }
              }
            }
          )
        ] }),
        ...restProps,
        ...getInputProps({
          ref: inputRef,
          /*  Empty onCall to avoid TS error
           *  See issue here: https://github.com/downshift-js/downshift/issues/718
           *  Downshift repo: https://github.com/downshift-js/downshift/tree/master
           */
          onChange: () => {
          },
          onBlur,
          "aria-labelledby": ariaLabelledBy
          // Label should be handled with the Field component
        })
      }
    ),
    /* @__PURE__ */ jsx(
      "div",
      {
        className: cx(styles.menu, !isOpen && styles.menuClosed),
        style: {
          ...floatStyles
        },
        ...getMenuProps({
          ref: floatingRef,
          "aria-labelledby": ariaLabelledBy
        }),
        children: isOpen && /* @__PURE__ */ jsx("ul", { style: { height: rowVirtualizer.getTotalSize() }, className: styles.menuUlContainer, children: rowVirtualizer.getVirtualItems().map((virtualRow) => {
          return /* @__PURE__ */ jsx(
            "li",
            {
              "data-index": virtualRow.index,
              className: cx(
                styles.option,
                selectedItem && items[virtualRow.index].value === selectedItem.value && styles.optionSelected,
                highlightedIndex === virtualRow.index && styles.optionFocused
              ),
              style: {
                height: virtualRow.size,
                transform: `translateY(${virtualRow.start}px)`
              },
              ...getItemProps({
                item: items[virtualRow.index],
                index: virtualRow.index
              }),
              children: /* @__PURE__ */ jsxs("div", { className: styles.optionBody, children: [
                /* @__PURE__ */ jsx("span", { className: styles.optionLabel, children: items[virtualRow.index].label }),
                items[virtualRow.index].description && /* @__PURE__ */ jsx("span", { className: styles.optionDescription, children: items[virtualRow.index].description })
              ] })
            },
            items[virtualRow.index].value + items[virtualRow.index].label
          );
        }) })
      }
    )
  ] });
};

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