/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-b67433b | Cube Dev Team */
import { extractStyles } from "../../../utils/styles.js";
import { useEventBus } from "../../../utils/react/useEventBus.js";
import { useEvent } from "../../../_internal/hooks/use-event.js";
import { _Text } from "../../content/Text.js";
import { LoadingIcon } from "../../../icons/LoadingIcon.js";
import { useWarn } from "../../../_internal/hooks/use-warn.js";
import { useProviderProps } from "../../../provider.js";
import { ItemAction } from "../../actions/ItemAction/ItemAction.js";
import { CloseIcon } from "../../../icons/CloseIcon.js";
import { DirectionIcon } from "../../../icons/DirectionIcon.js";
import { generateRandomId } from "../../../utils/random.js";
import { _ItemButton } from "../../actions/ItemButton/ItemButton.js";
import { useFormProps } from "../../form/Form/Form.js";
import { useFieldProps } from "../../form/Form/use-field/use-field-props.js";
import { wrapWithField } from "../../form/wrapper.js";
import { Dialog } from "../../overlays/Dialog/Dialog.js";
import { DialogTrigger } from "../../overlays/Dialog/DialogTrigger.js";
import { ListBox } from "../ListBox/ListBox.js";
import { processSelectionArray } from "../../../utils/selection.js";
import { FilterListBox } from "../FilterListBox/FilterListBox.js";
import { BASE_STYLES, COLOR_STYLES, OUTER_STYLES, filterBaseProps, tasty } from "@tenphi/tasty";
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
import { FocusScope, useKeyboard } from "react-aria";
import { Section, useListState } from "react-stately";

//#region src/components/fields/FilterPicker/FilterPicker.tsx
const PROP_STYLES = [
	...BASE_STYLES,
	...OUTER_STYLES,
	...COLOR_STYLES
];
const FilterPickerWrapper = tasty({
	qa: "FilterPicker",
	styles: {
		display: "inline-grid",
		flow: "column",
		gridRows: "1sf",
		placeContent: "stretch",
		placeItems: "stretch"
	}
});
const FilterPicker = forwardRef(function FilterPicker(props, ref) {
	props = useProviderProps(props);
	props = useFormProps(props);
	props = useFieldProps(props, { valuePropsMapper: ({ value, onChange }) => {
		const fieldProps = {};
		if (props.selectionMode === "multiple") fieldProps.selectedKeys = value || [];
		else fieldProps.selectedKey = value ?? null;
		fieldProps.onSelectionChange = (key) => {
			if (props.selectionMode === "multiple") if (key === "all") onChange("all");
			else onChange(key ? Array.isArray(key) ? key : [key] : []);
			else onChange(Array.isArray(key) ? key[0] : key);
		};
		return fieldProps;
	} });
	let { qa, label, extra, id, icon, rightIcon, prefix, suffix, hotkeys, triggerTooltip, triggerDescription, labelStyles, isRequired, necessityIndicator, validationState, isDisabled, isLoading, message, mods: externalMods, description, descriptionPlacement, placeholder, size = "medium", styles, listBoxStyles, popoverStyles, type = "outline", theme = "default", shape, labelSuffix, shouldFocusWrap, children, shouldFlip = true, containerPadding = 8, selectedKey, defaultSelectedKey, selectedKeys, defaultSelectedKeys, disabledKeys, onSelectionChange, selectionMode = "single", listStateRef, focusOnHover, showSelectAll, selectAllLabel = "All", items, header, footer, headerStyles, footerStyles, triggerStyles, allowsCustomValue, renderSummary, isCheckable, allValueProps, customValueProps, newCustomValueProps, searchPlaceholder, autoFocus, filter, emptyLabel, searchInputStyles, searchInputRef, listStyles, optionStyles, sectionStyles, headingStyles, listRef, disallowEmptySelection, shouldUseVirtualFocus, onEscape, onOptionClick, isClearable, searchValue, onSearchChange, sortSelectedToTop: sortSelectedToTopProp, onOpenChange, form, ...otherProps } = props;
	const sortSelectedToTopExplicit = sortSelectedToTopProp !== void 0;
	const sortSelectedToTop = sortSelectedToTopProp ?? (items ? true : false);
	styles = extractStyles(otherProps, PROP_STYLES, styles);
	const filterPickerId = useMemo(() => generateRandomId(), []);
	const { emit, on } = useEventBus();
	useWarn(isCheckable === false && selectionMode === "single", {
		key: ["filterpicker-checkable-single-mode"],
		args: ["CubeUIKit: isCheckable=false is not recommended in single selection mode as it may confuse users about selection behavior."]
	});
	useWarn(sortSelectedToTopExplicit && sortSelectedToTop && !items, {
		key: ["filterpicker-sort-selected-to-top-children"],
		args: ["FilterPicker: sortSelectedToTop only works with the items prop. Sorting will be skipped when using JSX children."]
	});
	const [internalSelectedKey, setInternalSelectedKey] = useState(defaultSelectedKey ?? null);
	const [internalSelectedKeys, setInternalSelectedKeys] = useState(defaultSelectedKeys ?? []);
	const [isPopoverOpen, setIsPopoverOpen] = useState(false);
	const cachedItemsOrder = useRef(null);
	const triggerRef = useRef(null);
	const triggerWidthRef = useRef(void 0);
	useEffect(() => {
		cachedItemsOrder.current = null;
	}, [items]);
	const isControlledSingle = selectedKey !== void 0;
	const isControlledMultiple = selectedKeys !== void 0;
	const effectiveSelectedKey = isControlledSingle ? selectedKey : internalSelectedKey;
	const effectiveSelectedKeys = isControlledMultiple ? selectedKeys : internalSelectedKeys;
	const localCollectionState = useListState({
		children,
		items,
		selectionMode: "none"
	});
	const { labelMap, keyMap } = useMemo(() => {
		const lm = /* @__PURE__ */ new Map();
		const km = /* @__PURE__ */ new Map();
		const traverse = (nodes) => {
			for (const node of nodes) if (node.type === "item") {
				const strKey = String(node.key);
				lm.set(strKey, node.textValue || strKey);
				km.set(strKey, node.key);
			} else if (node.childNodes) traverse(node.childNodes);
		};
		traverse(localCollectionState.collection);
		return {
			labelMap: lm,
			keyMap: km
		};
	}, [localCollectionState.collection]);
	const mappedSelectedKey = useMemo(() => {
		if (selectionMode !== "single" || effectiveSelectedKey == null) return null;
		const strKey = String(effectiveSelectedKey);
		return keyMap.get(strKey) ?? effectiveSelectedKey;
	}, [
		selectionMode,
		effectiveSelectedKey,
		keyMap
	]);
	const mappedSelectedKeys = useMemo(() => {
		if (selectionMode !== "multiple") return void 0;
		if (effectiveSelectedKeys === "all") return "all";
		if (Array.isArray(effectiveSelectedKeys)) return effectiveSelectedKeys.map((k) => {
			const strKey = String(k);
			return keyMap.get(strKey) ?? k;
		});
		return effectiveSelectedKeys;
	}, [
		selectionMode,
		effectiveSelectedKeys,
		keyMap
	]);
	const selectedLabels = useMemo(() => {
		if (selectionMode === "multiple" && effectiveSelectedKeys === "all") return Array.from(labelMap.values());
		return (selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? (effectiveSelectedKeys || []).map(String) : effectiveSelectedKey != null ? [String(effectiveSelectedKey)] : []).map((k) => labelMap.get(k) ?? k);
	}, [
		selectionMode,
		effectiveSelectedKey,
		effectiveSelectedKeys,
		labelMap
	]);
	const hasSelection = selectedLabels.length > 0;
	const latestSelectionRef = useRef({
		single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
		multiple: effectiveSelectedKeys === "all" ? "all" : (effectiveSelectedKeys ?? []).map(String)
	});
	useEffect(() => {
		latestSelectionRef.current = {
			single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
			multiple: effectiveSelectedKeys === "all" ? "all" : (effectiveSelectedKeys ?? []).map(String)
		};
	}, [effectiveSelectedKey, effectiveSelectedKeys]);
	const selectionsWhenClosed = useRef({
		single: null,
		multiple: []
	});
	useEffect(() => {
		if (!isPopoverOpen) selectionsWhenClosed.current = {
			single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
			multiple: effectiveSelectedKeys === "all" ? "all" : (effectiveSelectedKeys ?? []).map(String)
		};
	}, [
		effectiveSelectedKey,
		effectiveSelectedKeys,
		isPopoverOpen
	]);
	const handleOpenChange = useEvent((isOpen) => {
		if (isOpen === isPopoverOpen) return;
		if (isOpen) triggerWidthRef.current = triggerRef?.current?.UNSAFE_getDOMNode()?.offsetWidth;
		setIsPopoverOpen(isOpen);
		if (!isOpen) {
			selectionsWhenClosed.current = { ...latestSelectionRef.current };
			cachedItemsOrder.current = null;
		}
		onOpenChange?.(isOpen);
	});
	useEffect(() => {
		return on("popover:open", (data) => {
			if (data.menuId !== filterPickerId && isPopoverOpen) handleOpenChange(false);
		});
	}, [
		on,
		filterPickerId,
		isPopoverOpen,
		handleOpenChange
	]);
	useEffect(() => {
		if (isPopoverOpen) emit("popover:open", { menuId: filterPickerId });
	}, [
		isPopoverOpen,
		emit,
		filterPickerId
	]);
	const [shouldUpdatePosition, setShouldUpdatePosition] = useState(true);
	useEffect(() => {
		if (isPopoverOpen) {
			setShouldUpdatePosition(true);
			const timerId = window.setTimeout(() => setShouldUpdatePosition(false), 160);
			return () => window.clearTimeout(timerId);
		} else setShouldUpdatePosition(true);
	}, [isPopoverOpen]);
	const { keyboardProps } = useKeyboard({ onKeyDown: (e) => {
		if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !isPopoverOpen) {
			e.preventDefault();
			handleOpenChange(true);
		}
	} });
	const clearValue = useEvent(() => {
		if (selectionMode === "multiple") {
			if (!isControlledMultiple) setInternalSelectedKeys([]);
			onSelectionChange?.([]);
		} else {
			if (!isControlledSingle) setInternalSelectedKey(null);
			onSelectionChange?.(null);
		}
		handleOpenChange(false);
		triggerRef?.current?.focus?.();
		props.onClear?.();
		return false;
	});
	const finalItems = useMemo(() => {
		if (!items) return items;
		if (!sortSelectedToTop) return items;
		if (!isPopoverOpen) return items;
		if (cachedItemsOrder.current) return cachedItemsOrder.current;
		const selectedSet = /* @__PURE__ */ new Set();
		const addSelected = (key) => {
			if (key != null) selectedSet.add(String(key));
		};
		if (selectionMode === "multiple") {
			if (selectionsWhenClosed.current.multiple === "all") return items;
			selectionsWhenClosed.current.multiple.forEach(addSelected);
		} else if (selectionsWhenClosed.current.single != null) addSelected(selectionsWhenClosed.current.single);
		if (selectedSet.size === 0) return items;
		const getItemKey = (obj) => {
			if (obj == null || typeof obj !== "object") return void 0;
			const item = obj;
			if (item.key != null) return String(item.key);
			if (item.id != null) return String(item.id);
		};
		const sortArray = (arr) => {
			const selectedArr = [];
			const unselectedArr = [];
			arr.forEach((obj) => {
				const item = obj;
				if (obj && Array.isArray(item.children)) {
					const sortedChildren = sortArray(item.children);
					unselectedArr.push({
						...item,
						children: sortedChildren
					});
				} else {
					const key = getItemKey(obj);
					if (key && selectedSet.has(key)) selectedArr.push(obj);
					else unselectedArr.push(obj);
				}
			});
			return [...selectedArr, ...unselectedArr];
		};
		const sorted = sortArray(Array.isArray(items) ? items : Array.from(items));
		cachedItemsOrder.current = sorted;
		return sorted;
	}, [
		items,
		sortSelectedToTop,
		selectionMode,
		isPopoverOpen
	]);
	const triggerContent = useMemo(() => {
		if (typeof renderSummary === "function") {
			if (selectionMode === "single") return renderSummary({
				selectedLabel: selectedLabels[0],
				selectedKey: effectiveSelectedKey ?? null,
				selectedLabels,
				selectedKeys: effectiveSelectedKeys,
				selectionMode: "single"
			});
			return renderSummary({
				selectedLabels,
				selectedKeys: effectiveSelectedKeys,
				selectionMode: "multiple"
			});
		} else if (renderSummary === false) return null;
		if (!hasSelection) return /* @__PURE__ */ jsx(_Text.Placeholder, { children: placeholder });
		else if (selectionMode === "single") return selectedLabels[0] || null;
		else if (effectiveSelectedKeys === "all") return selectAllLabel;
		else return selectedLabels.join(", ") || null;
	}, [
		renderSummary,
		selectionMode,
		selectedLabels,
		effectiveSelectedKey,
		effectiveSelectedKeys,
		hasSelection,
		placeholder,
		selectAllLabel
	]);
	const showClearButton = isClearable && hasSelection && !isDisabled && !props.isReadOnly;
	const triggerElement = /* @__PURE__ */ jsx(_ItemButton, {
		ref: triggerRef,
		"data-popover-trigger": true,
		qa: qa || "FilterPicker",
		id,
		type,
		theme: validationState === "invalid" ? "danger" : theme,
		size,
		shape,
		isDisabled: isDisabled || isLoading,
		"data-input-type": "filterpicker",
		mods: {
			placeholder: !hasSelection,
			...externalMods
		},
		icon,
		rightIcon: isLoading ? /* @__PURE__ */ jsx(LoadingIcon, {}) : rightIcon !== void 0 ? rightIcon : showClearButton ? /* @__PURE__ */ jsx(ItemAction, {
			icon: /* @__PURE__ */ jsx(CloseIcon, {}),
			size,
			theme: validationState === "invalid" ? "danger" : void 0,
			qa: "FilterPickerClearButton",
			mods: { pressed: false },
			onPress: clearValue
		}) : /* @__PURE__ */ jsx(DirectionIcon, { to: isPopoverOpen ? "top" : "bottom" }),
		prefix,
		suffix,
		hotkeys,
		tooltip: triggerTooltip,
		description: triggerDescription,
		descriptionPlacement,
		styles: triggerStyles,
		...keyboardProps,
		"aria-label": `${props["aria-label"] ?? props.label ?? ""}`,
		children: triggerContent
	});
	const handleSelectionChange = useEvent((selection) => {
		if (selectionMode === "single") {
			if (!isControlledSingle) setInternalSelectedKey(selection);
		} else if (!isControlledMultiple) {
			let normalized = selection;
			if (selection === "all") normalized = "all";
			else if (Array.isArray(selection)) normalized = processSelectionArray(selection);
			else if (selection && typeof selection === "object" && selection instanceof Set) normalized = processSelectionArray(selection);
			setInternalSelectedKeys(normalized);
		}
		if (selectionMode === "single") latestSelectionRef.current.single = selection != null ? String(selection) : null;
		else if (selection === "all") latestSelectionRef.current.multiple = "all";
		else if (Array.isArray(selection)) latestSelectionRef.current.multiple = Array.from(new Set(processSelectionArray(selection)));
		else if (selection && typeof selection === "object" && selection instanceof Set) latestSelectionRef.current.multiple = Array.from(new Set(processSelectionArray(selection)));
		else latestSelectionRef.current.multiple = selection === "all" ? "all" : Array.isArray(selection) ? selection.map(String) : [];
		onSelectionChange?.(selection);
		if (selectionMode === "single") handleOpenChange(false);
	});
	const handleEscape = useEvent(() => {
		handleOpenChange(false);
	});
	const handleOptionClick = useEvent((key) => {
		if (selectionMode === "multiple" && isCheckable || key === "__ALL__") handleOpenChange(false);
	});
	return wrapWithField(/* @__PURE__ */ jsx(FilterPickerWrapper, {
		qa: "FilterPickerWrapper",
		styles,
		...filterBaseProps(otherProps, { eventProps: true }),
		children: /* @__PURE__ */ jsxs(DialogTrigger, {
			isDismissable: true,
			type: "popover",
			placement: "bottom start",
			isOpen: isPopoverOpen,
			containerPadding,
			shouldUpdatePosition,
			shouldFlip: shouldFlip && shouldUpdatePosition,
			shouldCloseOnInteractOutside: (el) => {
				const menuTriggerEl = el.closest("[data-popover-trigger]");
				if (!menuTriggerEl) return true;
				if (menuTriggerEl === triggerRef?.current?.UNSAFE_getDOMNode()) return true;
				return false;
			},
			onOpenChange: handleOpenChange,
			children: [triggerElement, () => /* @__PURE__ */ jsx(Dialog, {
				qa: "FilterPickerOverlay",
				display: "grid",
				styles: {
					gridRows: "1sf",
					width: "max($overlay-min-width, 30x) max-content 50vw",
					"$overlay-min-width": "30x",
					...popoverStyles
				},
				style: triggerWidthRef.current ? { "--overlay-min-width": `${triggerWidthRef.current}px` } : void 0,
				children: /* @__PURE__ */ jsx(FocusScope, {
					restoreFocus: true,
					children: /* @__PURE__ */ jsx(FilterListBox, {
						autoFocus: true,
						items: items ? finalItems : void 0,
						"aria-label": `${props["aria-label"] ?? props.label ?? ""} Picker`,
						_internalCollection: localCollectionState.collection,
						selectedKey: selectionMode === "single" ? mappedSelectedKey : void 0,
						selectedKeys: selectionMode === "multiple" ? mappedSelectedKeys : void 0,
						searchPlaceholder,
						filter,
						searchValue,
						listStyles,
						optionStyles,
						sectionStyles,
						headingStyles,
						listRef,
						disallowEmptySelection,
						emptyLabel,
						searchInputStyles,
						searchInputRef,
						disabledKeys,
						focusOnHover,
						shouldFocusWrap,
						allowsCustomValue,
						selectionMode,
						validationState,
						isDisabled,
						isLoading,
						stateRef: listStateRef,
						isCheckable,
						mods: { popover: true },
						size: size === "small" ? "medium" : size,
						showSelectAll,
						selectAllLabel,
						header,
						footer,
						headerStyles,
						footerStyles,
						allValueProps,
						customValueProps,
						newCustomValueProps,
						onSearchChange,
						onEscape: handleEscape,
						onOptionClick: handleOptionClick,
						onSelectionChange: handleSelectionChange,
						children: children ? children : void 0
					})
				})
			})]
		})
	}), ref, props);
});
FilterPicker.Item = ListBox.Item;
FilterPicker.Section = Section;
Object.defineProperty(FilterPicker, "cubeInputType", {
	value: "FilterPicker",
	enumerable: false,
	configurable: false
});

//#endregion
export { FilterPicker };
//# sourceMappingURL=FilterPicker.js.map