import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { forwardRef, useRef, useId, useMemo, useState, useCallback, useEffect } from 'react';
import { u as useToggleSelection, M as MultiSelectOptions } from './useToggleSelection-D_2qS0P1.js';
import { a as useSelectOrchestration, b as useProcessedOptions, c as buildSelectItems, d as useDebouncedCallback, e as OptionsDialog, f as OptionsPopover, g as defaultSyncFilter, t as toSyncFilterFn } from './syncFilterUtils-BLcRXQfd.js';
import { u as useMenuInteraction } from './useMenuInteraction-BwZ2ORo9.js';
import { w as warnOnce } from './warnOnce-Y9PRHcU4.js';
import { S as SearchField } from './SearchField-CsRGYZx3.js';

const MultiSelectMenu = forwardRef((props, ref) => {
  const triggerRef = useRef(null);
  const searchRef = useRef(null);
  const {
    id: idProp,
    value: selectedOptions,
    initialLoad: initialLoadProp,
    displayMenuAs: displayMenuAsProp,
    lazy,
    loadOptions: loadOptionsProp,
    label,
    searchPlaceholder,
    debounceMs = 200,
    onSelectedOptionsChange,
    cache,
    pinned,
    selectAll: selectAllProp,
    selectFiltered: selectFilteredProp,
    virtualize,
    disableSearch,
    popoverWidth,
    trigger,
    onSearchChange,
    onMenuKeyDown,
    onImplicitClose,
    onExplicitClose
  } = props;
  const groupToString = "groupToString" in props ? props.groupToString : void 0;
  const groupSorter = "groupSorter" in props ? props.groupSorter : void 0;
  const autoId = useId();
  const id = idProp ?? autoId;
  if (disableSearch && selectFilteredProp) {
    warnOnce(
      "MultiSelectMenu: `selectFiltered` has no effect when `disableSearch` is true because there is no search input to produce filtered results."
    );
  }
  const {
    displayAs,
    initialLoad,
    initialLoadPerformed,
    setInitialLoadPerformed,
    options,
    loading,
    loadingMore,
    hasMore,
    loadOptions,
    loadMore
  } = useSelectOrchestration({
    lazy,
    loadOptions: loadOptionsProp,
    cache,
    lazyOptions: "lazyOptions" in props ? props.lazyOptions : void 0,
    initialLoad: initialLoadProp,
    displayMenuAs: displayMenuAsProp,
    ref
  });
  const selectAll = useMemo(
    () => selectAllProp ? {
      label: selectAllProp.label ?? "Select All",
      onClick: selectAllProp.onClick,
      checkState: selectAllProp.checkState === true ? "checked" : selectAllProp.checkState === false ? "unchecked" : selectAllProp.checkState ?? "indeterminate"
    } : void 0,
    [selectAllProp]
  );
  const selectFiltered = useMemo(
    () => selectFilteredProp ? (searchValue2) => {
      const config = selectFilteredProp(searchValue2);
      return {
        label: config.label,
        onClick: config.onClick,
        checkState: config.checkState === true ? "checked" : config.checkState === false ? "unchecked" : config.checkState ?? "indeterminate"
      };
    } : void 0,
    [selectFilteredProp]
  );
  const [inputValue, setInputValue] = useState("");
  const searchValue = disableSearch ? "" : inputValue;
  const { pinnedSections, ungroupedItems, groupSections } = useProcessedOptions(
    {
      options,
      pinned,
      searchValue,
      groupToString,
      groupSorter
    }
  );
  const { handleItemClick } = useToggleSelection({
    options,
    pinnedSections,
    selectedOptions,
    onSelectedOptionsChange
  });
  const bulkActionItems = useMemo(() => {
    const items2 = [];
    if (selectAll && !searchValue) {
      items2.push({
        id: "select-all",
        type: "select-all",
        original: { id: "select-all", label: selectAll.label ?? "Select All" },
        checkState: selectAll.checkState
      });
    }
    if (selectFiltered && searchValue && !loading) {
      const config = selectFiltered(searchValue);
      items2.push({
        id: "select-filtered",
        type: "select-filtered",
        original: {
          id: "select-filtered",
          label: config.label ?? "Select Filtered"
        },
        checkState: config.checkState
      });
    }
    return items2;
  }, [selectAll, selectFiltered, searchValue, loading]);
  const { items, sectionsMeta } = useMemo(
    () => buildSelectItems({
      prefixItems: bulkActionItems,
      pinnedSections,
      groupSections,
      ungroupedItems
    }),
    [bulkActionItems, pinnedSections, groupSections, ungroupedItems]
  );
  const selectedItemIds = useMemo(
    () => new Set(selectedOptions.map((o) => o.id)),
    [selectedOptions]
  );
  const handleItemActivate = useCallback(
    (item) => {
      if (item.type === "select-all") {
        selectAll?.onClick();
      } else if (item.type === "select-filtered" && selectFiltered) {
        const config = selectFiltered(searchValue);
        config.onClick();
      } else if (item.type === "option" || item.type === "pinned-option" || item.type === "grouped-option") {
        handleItemClick(item.original);
      }
    },
    [selectAll, selectFiltered, searchValue, handleItemClick]
  );
  const {
    isOpen,
    closeMenu,
    highlightedIndex,
    getTriggerProps,
    getMenuProps,
    getItemProps,
    listRef,
    menuContainerRef,
    handleKeyDown
  } = useMenuInteraction({
    items,
    sectionsMeta,
    onItemActivate: handleItemActivate,
    selectedItemIds,
    displayAs,
    closeOnActivate: false,
    id,
    triggerRef,
    label,
    onImplicitClose,
    onExplicitClose
  });
  const debouncedOptionLoader = useDebouncedCallback((value) => {
    loadOptions(value, { initial: true });
  }, debounceMs);
  const handleInputChange = useCallback(
    (e) => {
      const value = e.target.value;
      setInputValue(value);
      debouncedOptionLoader(value);
      onSearchChange?.(value);
    },
    [debouncedOptionLoader, onSearchChange]
  );
  const handleInputKeyDown = useCallback(
    (e) => {
      onMenuKeyDown?.(e);
      handleKeyDown(e);
    },
    [handleKeyDown, onMenuKeyDown]
  );
  const getMenuPropsWithKeyDown = useCallback(
    (opts) => {
      const menuProps = getMenuProps(opts);
      if (!onMenuKeyDown) return menuProps;
      return {
        ...menuProps,
        onKeyDown: (e) => {
          onMenuKeyDown(e);
          menuProps.onKeyDown(e);
        }
      };
    },
    [getMenuProps, onMenuKeyDown]
  );
  useEffect(() => {
    const performInitialLoad = async () => {
      if (initialLoad === "immediate" && !initialLoadPerformed) {
        await loadOptions("", { initial: true });
        setInitialLoadPerformed(true);
      }
    };
    performInitialLoad();
  }, [loadOptions, initialLoadPerformed, initialLoad, setInitialLoadPerformed]);
  const prevIsOpenRef = useRef(false);
  useEffect(() => {
    const wasOpen = prevIsOpenRef.current;
    prevIsOpenRef.current = isOpen;
    if (isOpen && !wasOpen) {
      if (initialLoad === "open" && !initialLoadPerformed) {
        loadOptions("", { initial: true }).then(() => {
          setInitialLoadPerformed(true);
        });
      }
    }
    if (!isOpen && wasOpen) {
      setInputValue("");
      loadOptions("", { initial: true });
    }
  }, [
    isOpen,
    initialLoad,
    initialLoadPerformed,
    loadOptions,
    setInitialLoadPerformed
  ]);
  useEffect(() => {
    if (!isOpen || displayAs !== "popover") return;
    const frameId = requestAnimationFrame(() => {
      if (!disableSearch) {
        searchRef.current?.focus();
      } else {
        menuContainerRef.current?.focus();
      }
    });
    return () => cancelAnimationFrame(frameId);
  }, [isOpen, displayAs, disableSearch, menuContainerRef]);
  const handleLoadMore = async () => {
    await loadMore(searchValue);
  };
  const handleClickOutside = useCallback(() => {
    closeMenu({ restoreFocus: false });
  }, [closeMenu]);
  const triggerProps = getTriggerProps();
  const menuPropsForAria = getMenuProps();
  const activeDescendant = menuPropsForAria["aria-activedescendant"];
  const handleSearchClear = useCallback(() => {
    setInputValue("");
    debouncedOptionLoader("");
    onSearchChange?.("");
  }, [debouncedOptionLoader, onSearchChange]);
  const searchInput = !disableSearch ? /* @__PURE__ */ jsx(
    SearchField,
    {
      ref: searchRef,
      value: inputValue,
      onChange: handleInputChange,
      onKeyDown: handleInputKeyDown,
      onClear: handleSearchClear,
      "aria-activedescendant": activeDescendant,
      "aria-controls": menuPropsForAria.id,
      placeholder: searchPlaceholder,
      type: "search"
    }
  ) : null;
  if (displayAs === "dialog") {
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      trigger(triggerProps),
      /* @__PURE__ */ jsx(
        OptionsDialog,
        {
          id: `${id}-dialog`,
          isOpen,
          onClose: closeMenu,
          title: label,
          field: searchInput ?? void 0,
          initialFocusResolver: !disableSearch ? (elements) => elements.find((el) => el.tagName === "INPUT") || elements[0] : void 0,
          children: /* @__PURE__ */ jsx(
            MultiSelectOptions,
            {
              ref: listRef,
              isOpen: true,
              items,
              sectionsMeta,
              getMenuProps: (opts) => {
                const menuProps = getMenuPropsWithKeyDown(opts);
                if (disableSearch) {
                  return menuProps;
                }
                return { ...menuProps, tabIndex: -1 };
              },
              getItemProps,
              highlightedIndex,
              selectedOptions,
              hasMore,
              onLoadMore: handleLoadMore,
              loading,
              loadingMore,
              virtualize
            }
          )
        }
      )
    ] });
  }
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    trigger(triggerProps),
    /* @__PURE__ */ jsxs(
      OptionsPopover,
      {
        id: `${id}-popover`,
        referenceElement: triggerRef,
        open: isOpen && displayAs === "popover",
        onClickOutside: handleClickOutside,
        width: popoverWidth ?? 320,
        children: [
          searchInput,
          /* @__PURE__ */ jsx(
            MultiSelectOptions,
            {
              ref: listRef,
              isOpen,
              items,
              sectionsMeta,
              getMenuProps: (opts) => {
                const menuProps = getMenuPropsWithKeyDown(opts);
                if (disableSearch) {
                  return menuProps;
                }
                return { ...menuProps, tabIndex: -1 };
              },
              getItemProps,
              highlightedIndex,
              selectedOptions,
              hasMore,
              onLoadMore: handleLoadMore,
              loading,
              loadingMore,
              virtualize
            }
          )
        ]
      }
    )
  ] });
});
MultiSelectMenu.displayName = "MultiSelectMenu";

const MultiSelectMenuSync = (props) => {
  const {
    options,
    filter: filterProp = defaultSyncFilter,
    selectAll: selectAllProp,
    selectFiltered: selectFilteredProp,
    value,
    onSelectedOptionsChange,
    ...rest
  } = props;
  const filter = useMemo(() => toSyncFilterFn(filterProp), [filterProp]);
  const selectAllConfig = useMemo(() => {
    if (!selectAllProp) return void 0;
    const enabledOptions = options.filter((opt) => !opt.disabled);
    const enabledIds = new Set(enabledOptions.map((opt) => opt.id));
    const selectedCount = value.filter((v) => enabledIds.has(v.id)).length;
    const totalCount = enabledOptions.length;
    const allSelected = selectedCount === totalCount;
    const labelProp = typeof selectAllProp === "object" ? selectAllProp.label : void 0;
    const label = typeof labelProp === "function" ? labelProp(allSelected) : labelProp;
    const checkState = allSelected ? "checked" : selectedCount > 0 ? "indeterminate" : "unchecked";
    const handleClick = () => {
      if (allSelected) {
        onSelectedOptionsChange([]);
      } else {
        onSelectedOptionsChange(enabledOptions);
      }
    };
    return {
      label,
      onClick: handleClick,
      checkState
    };
  }, [selectAllProp, options, value, onSelectedOptionsChange]);
  const selectFilteredConfig = useMemo(() => {
    if (!selectFilteredProp) return void 0;
    return (searchValue) => {
      const filteredOptions = filter(options, searchValue);
      const enabledFilteredOptions = filteredOptions.filter(
        (opt) => !opt.disabled
      );
      const selectedIds = new Set(value.map((v) => v.id));
      const allFilteredSelected = enabledFilteredOptions.length > 0 && enabledFilteredOptions.every((opt) => selectedIds.has(opt.id));
      const someFilteredSelected = enabledFilteredOptions.some(
        (opt) => selectedIds.has(opt.id)
      );
      const label = typeof selectFilteredProp === "function" ? selectFilteredProp(searchValue).label : void 0;
      const checkState = allFilteredSelected ? "checked" : someFilteredSelected ? "indeterminate" : "unchecked";
      const handleClick = () => {
        if (allFilteredSelected) {
          const filteredIds = new Set(enabledFilteredOptions.map((o) => o.id));
          onSelectedOptionsChange(value.filter((v) => !filteredIds.has(v.id)));
        } else {
          const currentIds = new Set(value.map((v) => v.id));
          const newSelections = enabledFilteredOptions.filter(
            (opt) => !currentIds.has(opt.id)
          );
          onSelectedOptionsChange([...value, ...newSelections]);
        }
      };
      return {
        label,
        onClick: handleClick,
        checkState
      };
    };
  }, [selectFilteredProp, options, value, onSelectedOptionsChange, filter]);
  const fieldRef = useRef(null);
  const prevOptionsRef = useRef(options);
  useEffect(() => {
    if (prevOptionsRef.current !== options) {
      prevOptionsRef.current = options;
      fieldRef.current?.invalidate();
    }
  }, [options]);
  return /* @__PURE__ */ jsx(
    MultiSelectMenu,
    {
      ref: fieldRef,
      lazy: false,
      loadOptions: (searchValue) => filter(options, searchValue),
      debounceMs: 0,
      value,
      onSelectedOptionsChange,
      selectAll: selectAllConfig,
      selectFiltered: selectFilteredConfig,
      ...rest
    }
  );
};

export { MultiSelectMenu as M, MultiSelectMenuSync as a };
//# sourceMappingURL=MultiSelectMenuSync-dgO9SmHi.js.map
