/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-e694c50 | 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 { 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/Picker/Picker.tsx
const PROP_STYLES = [
	...BASE_STYLES,
	...OUTER_STYLES,
	...COLOR_STYLES
];
const PickerWrapper = tasty({
	qa: "PickerWrapper",
	styles: {
		display: "inline-grid",
		flow: "column",
		gridRows: "1sf",
		placeContent: "stretch",
		placeItems: "stretch"
	}
});
const Picker = forwardRef(function Picker(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 { id, qa, label, extra, 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, renderSummary, isCheckable, allValueProps, listStyles, optionStyles, sectionStyles, headingStyles, listRef, disallowEmptySelection, shouldUseVirtualFocus, onEscape, onOptionClick, isClearable, onClear, sortSelectedToTop, onOpenChange, listStateRef: externalListStateRef, ...otherProps } = props;
	styles = extractStyles(otherProps, PROP_STYLES, styles);
	const pickerId = useMemo(() => generateRandomId(), []);
	const { emit, on } = useEventBus();
	useWarn(isCheckable === false && selectionMode === "single", {
		key: ["picker-checkable-single-mode"],
		args: ["CubeUIKit: isCheckable=false is not recommended in single selection mode as it may confuse users about selection behavior."]
	});
	const [internalSelectedKey, setInternalSelectedKey] = useState(defaultSelectedKey ?? null);
	const [internalSelectedKeys, setInternalSelectedKeys] = useState(defaultSelectedKeys ?? []);
	const [isPopoverOpen, setIsPopoverOpen] = useState(false);
	const triggerRef = useRef(null);
	const triggerWidthRef = useRef(void 0);
	const isControlledSingle = selectedKey !== void 0;
	const isControlledMultiple = selectedKeys !== void 0;
	const effectiveSelectedKey = isControlledSingle ? selectedKey : internalSelectedKey;
	const effectiveSelectedKeys = isControlledMultiple ? selectedKeys : internalSelectedKeys;
	const internalListStateRef = useRef(null);
	useEffect(() => {
		if (externalListStateRef && internalListStateRef.current) externalListStateRef.current = internalListStateRef.current;
	}, [externalListStateRef]);
	const cachedItemsOrder = useRef(null);
	const latestSelectionRef = useRef({
		single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
		multiple: selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? (effectiveSelectedKeys || []).map(String) : []
	});
	useEffect(() => {
		latestSelectionRef.current = {
			single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
			multiple: selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? (effectiveSelectedKeys || []).map(String) : []
		};
	}, [
		effectiveSelectedKey,
		effectiveSelectedKeys,
		selectionMode
	]);
	const selectionWhenClosed = useRef({
		single: null,
		multiple: []
	});
	const sortSelectedToTopExplicit = sortSelectedToTop !== void 0;
	const shouldSortSelectedToTop = sortSelectedToTop ?? (items ? true : false);
	useWarn(sortSelectedToTopExplicit && shouldSortSelectedToTop && !items, {
		key: ["picker-sort-selected-to-top-children"],
		args: ["Picker: sortSelectedToTop only works with the items prop. Sorting will be skipped when using JSX children."]
	});
	useEffect(() => {
		cachedItemsOrder.current = null;
	}, [items]);
	useEffect(() => {
		if (!isPopoverOpen) selectionWhenClosed.current = {
			single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
			multiple: selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? (effectiveSelectedKeys || []).map(String) : []
		};
	}, [
		effectiveSelectedKey,
		effectiveSelectedKeys,
		isPopoverOpen,
		selectionMode
	]);
	const finalItems = useMemo(() => {
		if (!items || !shouldSortSelectedToTop) return items;
		if (!isPopoverOpen) return items;
		if (cachedItemsOrder.current) return cachedItemsOrder.current;
		const selectedKeySet = /* @__PURE__ */ new Set();
		if (selectionMode === "multiple") {
			if (selectionWhenClosed.current.multiple.length === 0 || effectiveSelectedKeys === "all") return items;
			selectionWhenClosed.current.multiple.forEach((k) => selectedKeySet.add(k));
		} else if (selectionWhenClosed.current.single) selectedKeySet.add(selectionWhenClosed.current.single);
		if (selectedKeySet.size === 0) return items;
		const itemsArray = Array.isArray(items) ? items : Array.from(items);
		const selectedItems = [];
		const unselectedItems = [];
		itemsArray.forEach((item) => {
			const key = item?.key ?? item?.id;
			if (key != null && selectedKeySet.has(String(key))) selectedItems.push(item);
			else unselectedItems.push(item);
		});
		const sorted = [...selectedItems, ...unselectedItems];
		cachedItemsOrder.current = sorted;
		return sorted;
	}, [
		items,
		shouldSortSelectedToTop,
		selectionMode,
		isPopoverOpen
	]);
	const localCollectionState = useListState({
		children,
		items: finalItems,
		selectionMode: "none"
	});
	const selectedLabels = useMemo(() => {
		const collection = localCollectionState?.collection;
		if (selectionMode === "multiple" && effectiveSelectedKeys === "all") {
			if (!collection) return [];
			const labels = [];
			for (const item of collection) if (item.type === "item") labels.push(item.textValue || String(item.key));
			return labels;
		}
		return (selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? effectiveSelectedKeys || [] : effectiveSelectedKey != null ? [effectiveSelectedKey] : []).map((key) => {
			return (collection?.getItem(key))?.textValue || String(key);
		}).filter(Boolean);
	}, [
		selectionMode,
		effectiveSelectedKeys,
		effectiveSelectedKey,
		localCollectionState?.collection
	]);
	const hasSelection = selectedLabels.length > 0;
	const handleOpenChange = useEvent((isOpen) => {
		if (isOpen === isPopoverOpen) return;
		if (isOpen) triggerWidthRef.current = triggerRef?.current?.UNSAFE_getDOMNode()?.offsetWidth;
		setIsPopoverOpen(isOpen);
		if (!isOpen) {
			selectionWhenClosed.current = { ...latestSelectionRef.current };
			cachedItemsOrder.current = null;
		}
		onOpenChange?.(isOpen);
	});
	useEffect(() => {
		return on("popover:open", (data) => {
			if (data.menuId !== pickerId && isPopoverOpen) handleOpenChange(false);
		});
	}, [
		on,
		pickerId,
		isPopoverOpen,
		handleOpenChange
	]);
	useEffect(() => {
		if (isPopoverOpen) emit("popover:open", { menuId: pickerId });
	}, [
		isPopoverOpen,
		emit,
		pickerId
	]);
	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?.();
		onClear?.();
		return false;
	});
	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,
		id,
		qa: qa || "PickerTrigger",
		type,
		theme: validationState === "invalid" ? "danger" : theme,
		size,
		shape,
		isDisabled: isDisabled || isLoading,
		"data-input-type": "picker",
		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: "PickerClearButton",
			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 = [];
		else if (Array.isArray(selection)) latestSelectionRef.current.multiple = processSelectionArray(selection);
		else if (selection && typeof selection === "object" && selection instanceof Set) latestSelectionRef.current.multiple = processSelectionArray(selection);
		else latestSelectionRef.current.multiple = [];
		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(PickerWrapper, {
		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: "PickerOverlay",
				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(ListBox, {
						autoFocus: true,
						items: items ? finalItems : void 0,
						"aria-label": `${props["aria-label"] ?? props.label ?? ""} Picker`,
						selectedKey: selectionMode === "single" ? effectiveSelectedKey : void 0,
						selectedKeys: selectionMode === "multiple" ? effectiveSelectedKeys : void 0,
						listStyles,
						optionStyles,
						sectionStyles,
						headingStyles,
						listRef,
						disallowEmptySelection,
						disabledKeys,
						focusOnHover,
						shouldFocusWrap,
						selectionMode,
						validationState,
						isDisabled,
						isLoading,
						stateRef: internalListStateRef,
						isCheckable,
						shape: "popover",
						size: "medium",
						showSelectAll,
						selectAllLabel,
						header,
						footer,
						headerStyles,
						footerStyles,
						qa: `${props.qa || "Picker"}ListBox`,
						allValueProps,
						onEscape: handleEscape,
						onOptionClick: handleOptionClick,
						onSelectionChange: handleSelectionChange,
						children
					})
				})
			})]
		})
	}), ref, props);
});
Picker.Item = ListBox.Item;
Picker.Section = Section;
Object.defineProperty(Picker, "cubeInputType", {
	value: "Picker",
	enumerable: false,
	configurable: false
});

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