import { debounce } from 'lodash';
import { useMemo, useState, useCallback } from 'react';
import { t } from '@grafana/i18n';
import { itemToString, fuzzyFind } from './filter.mjs';
import { useLatestAsyncCall, StaleResultError } from './useLatestAsyncCall.mjs';

"use strict";
const asyncNoop = () => Promise.resolve([]);
const DEBOUNCE_TIME_MS = 200;
function useOptions(rawOptions, createCustomValue) {
  const isAsync = typeof rawOptions === "function";
  const loadOptions = useLatestAsyncCall(isAsync ? rawOptions : asyncNoop);
  const debouncedLoadOptions = useMemo(
    () => debounce((searchTerm) => {
      return loadOptions(searchTerm).then((options) => {
        setAsyncOptions(options);
        setAsyncLoading(false);
        setAsyncError(false);
      }).catch((error) => {
        if (!(error instanceof StaleResultError)) {
          setAsyncError(true);
          setAsyncLoading(false);
          if (error) {
            console.error("Error loading async options for Combobox", error);
          }
        }
      });
    }, DEBOUNCE_TIME_MS),
    [loadOptions]
  );
  const [asyncOptions, setAsyncOptions] = useState([]);
  const [asyncLoading, setAsyncLoading] = useState(false);
  const [asyncError, setAsyncError] = useState(false);
  const [userTypedSearch, setUserTypedSearch] = useState("");
  const addCustomValue = useCallback(
    (opts) => {
      let currentOptions = opts;
      if (createCustomValue && userTypedSearch) {
        const customValueExists = opts.some((opt) => opt.value === userTypedSearch);
        if (!customValueExists) {
          currentOptions = currentOptions.slice();
          currentOptions.unshift({
            label: userTypedSearch,
            value: userTypedSearch,
            description: t("combobox.custom-value.description", "Use custom value")
          });
        }
      }
      return currentOptions;
    },
    [createCustomValue, userTypedSearch]
  );
  const updateOptions = useCallback(
    (inputValue) => {
      setUserTypedSearch(inputValue);
      if (isAsync) {
        setAsyncLoading(true);
        debouncedLoadOptions(inputValue);
      }
    },
    [debouncedLoadOptions, isAsync]
  );
  const stringifiedOptions = useMemo(() => {
    return isAsync ? [] : rawOptions.map(itemToString);
  }, [isAsync, rawOptions]);
  const filteredOptions = useMemo(() => {
    if (isAsync) {
      return asyncOptions;
    }
    return fuzzyFind(rawOptions, stringifiedOptions, userTypedSearch);
  }, [asyncOptions, isAsync, rawOptions, stringifiedOptions, userTypedSearch]);
  const [finalOptions, groupStartIndices] = useMemo(() => {
    const { options, groupStartIndices: groupStartIndices2 } = sortByGroup(filteredOptions);
    return [addCustomValue(options), groupStartIndices2];
  }, [filteredOptions, addCustomValue]);
  return { options: finalOptions, groupStartIndices, updateOptions, asyncLoading, asyncError };
}
function sortByGroup(options) {
  var _a, _b;
  const groupedOptions = /* @__PURE__ */ new Map();
  const groupStartIndices = /* @__PURE__ */ new Map();
  for (const option of options) {
    const group = option.group;
    const existing = groupedOptions.get(group);
    if (existing) {
      existing.push(option);
    } else {
      groupedOptions.set(group, [option]);
    }
  }
  if (groupedOptions.size <= 1) {
    if ((_a = options[0]) == null ? void 0 : _a.group) {
      groupStartIndices.set((_b = options[0]) == null ? void 0 : _b.group, 0);
    }
    return {
      options,
      groupStartIndices
    };
  }
  const result = new Array(options.length);
  let currentIndex = 0;
  for (const [group, groupOptions] of groupedOptions) {
    if (group) {
      groupStartIndices.set(group, currentIndex);
    }
    for (const option of groupOptions) {
      result[currentIndex++] = option;
    }
  }
  return {
    options: result,
    groupStartIndices
  };
}

export { DEBOUNCE_TIME_MS, sortByGroup, useOptions };
//# sourceMappingURL=useOptions.mjs.map
