/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-a795c5b | Cube Dev Team */
import { extractStyles } from "../../../tasty/utils/styles.js";
import { BASE_STYLES, COLOR_STYLES, OUTER_STYLES } from "../../../tasty/styles/list.js";
import { tasty } from "../../../tasty/tasty.js";
import { filterBaseProps } from "../../../tasty/utils/filter-base-props.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 { _ItemButton } from "../../actions/ItemButton/ItemButton.js";
import { generateRandomId } from "../../../utils/random.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 { forwardRef, useCallback, 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 isControlledSingle = selectedKey !== void 0;
	const isControlledMultiple = selectedKeys !== void 0;
	const effectiveSelectedKey = isControlledSingle ? selectedKey : internalSelectedKey;
	const effectiveSelectedKeys = isControlledMultiple ? selectedKeys : internalSelectedKeys;
	const processSelectionArray = (iterable) => {
		const resultSet = /* @__PURE__ */ new Set();
		for (const key of iterable) {
			const nKey = String(key);
			if (resultSet.has(nKey)) resultSet.delete(nKey);
			else resultSet.add(nKey);
		}
		return Array.from(resultSet);
	};
	const internalListStateRef = useRef(null);
	useEffect(() => {
		if (externalListStateRef && internalListStateRef.current) externalListStateRef.current = internalListStateRef.current;
	}, [externalListStateRef]);
	const cachedItemsOrder = useRef(null);
	const selectionWhenClosed = useRef({
		single: null,
		multiple: []
	});
	const sortSelectedToTopExplicit = sortSelectedToTop !== void 0;
	const shouldSortSelectedToTop = sortSelectedToTop ?? (items ? true : false);
	useEffect(() => {
		cachedItemsOrder.current = null;
	}, [items]);
	useEffect(() => {
		if (!isPopoverOpen) {
			selectionWhenClosed.current = {
				single: effectiveSelectedKey != null ? String(effectiveSelectedKey) : null,
				multiple: selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? (effectiveSelectedKeys || []).map(String) : []
			};
			cachedItemsOrder.current = null;
		}
	}, [
		isPopoverOpen,
		effectiveSelectedKey,
		effectiveSelectedKeys,
		selectionMode
	]);
	useEffect(() => {
		onOpenChange?.(isPopoverOpen);
	}, [isPopoverOpen]);
	const finalItems = useCallback(() => {
		if (!items || !shouldSortSelectedToTop) return items;
		if (cachedItemsOrder.current) return cachedItemsOrder.current;
		if (sortSelectedToTopExplicit && !items) {
			console.warn("Picker: sortSelectedToTop only works with the items prop. Sorting will be skipped when using JSX children.");
			return items;
		}
		const selectedKeys = /* @__PURE__ */ new Set();
		if (selectionMode === "multiple") {
			if (selectionWhenClosed.current.multiple.length === 0 || effectiveSelectedKeys === "all") return items;
			selectionWhenClosed.current.multiple.forEach((k) => selectedKeys.add(k));
		} else if (selectionWhenClosed.current.single) selectedKeys.add(selectionWhenClosed.current.single);
		if (selectedKeys.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 && selectedKeys.has(String(key))) selectedItems.push(item);
			else unselectedItems.push(item);
		});
		const sorted = [...selectedItems, ...unselectedItems];
		if (isPopoverOpen) cachedItemsOrder.current = sorted;
		return sorted;
	}, [
		items,
		shouldSortSelectedToTop,
		sortSelectedToTopExplicit,
		selectionMode,
		effectiveSelectedKeys,
		isPopoverOpen
	])();
	const localCollectionState = useListState({
		children,
		items: finalItems,
		selectionMode: "none"
	});
	const getItemLabel = useCallback((key) => {
		return (localCollectionState?.collection?.getItem(key))?.textValue || String(key);
	}, [localCollectionState?.collection]);
	const selectedLabels = useMemo(() => {
		const keysToGet = selectionMode === "multiple" && effectiveSelectedKeys !== "all" ? effectiveSelectedKeys || [] : effectiveSelectedKey != null ? [effectiveSelectedKey] : [];
		if (selectionMode === "multiple" && effectiveSelectedKeys === "all") {
			if (!localCollectionState?.collection) return [];
			const labels = [];
			for (const item of localCollectionState.collection) if (item.type === "item") labels.push(item.textValue || String(item.key));
			return labels;
		}
		return keysToGet.map((key) => getItemLabel(key)).filter(Boolean);
	}, [
		selectionMode,
		effectiveSelectedKeys,
		effectiveSelectedKey,
		getItemLabel,
		localCollectionState?.collection
	]);
	const hasSelection = selectedLabels.length > 0;
	const renderTriggerContent = () => {
		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;
		let content = "";
		if (!hasSelection) return /* @__PURE__ */ jsx(_Text.Placeholder, { children: placeholder });
		else if (selectionMode === "single") content = selectedLabels[0];
		else if (effectiveSelectedKeys === "all") content = selectAllLabel;
		else content = selectedLabels.join(", ");
		if (!content) return null;
		return content;
	};
	const [shouldUpdatePosition, setShouldUpdatePosition] = useState(true);
	const triggerWidth = triggerRef?.current?.UNSAFE_getDOMNode()?.offsetWidth;
	const renderTrigger = (state) => {
		useEffect(() => {
			return on("popover:open", (data) => {
				if (data.menuId !== pickerId && state.isOpen) state.close();
			});
		}, [
			on,
			pickerId,
			state
		]);
		useEffect(() => {
			if (state.isOpen) emit("popover:open", { menuId: pickerId });
		}, [
			state.isOpen,
			emit,
			pickerId
		]);
		useEffect(() => {
			if (state.isOpen !== isPopoverOpen) setIsPopoverOpen(state.isOpen);
		}, [state.isOpen, isPopoverOpen]);
		const { keyboardProps } = useKeyboard({ onKeyDown: (e) => {
			if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !state.isOpen) {
				e.preventDefault();
				state.open();
			}
		} });
		useEffect(() => {
			if (state.isOpen) {
				setShouldUpdatePosition(true);
				const id = window.setTimeout(() => setShouldUpdatePosition(false), 160);
				return () => window.clearTimeout(id);
			} else setShouldUpdatePosition(true);
		}, [state.isOpen]);
		let showClearButton = isClearable && hasSelection && !isDisabled && !props.isReadOnly;
		let clearValue = useEvent(() => {
			if (selectionMode === "multiple") {
				if (!isControlledMultiple) setInternalSelectedKeys([]);
				onSelectionChange?.([]);
			} else {
				if (!isControlledSingle) setInternalSelectedKey(null);
				onSelectionChange?.(null);
			}
			if (state.isOpen) state.close();
			triggerRef?.current?.focus?.();
			onClear?.();
			return false;
		});
		return /* @__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: state.isOpen ? "top" : "bottom" }),
			prefix,
			suffix,
			hotkeys,
			tooltip: triggerTooltip,
			description: triggerDescription,
			descriptionPlacement,
			styles: triggerStyles,
			...keyboardProps,
			"aria-label": `${props["aria-label"] ?? props.label ?? ""}`,
			children: renderTriggerContent()
		});
	};
	return wrapWithField(/* @__PURE__ */ jsx(PickerWrapper, {
		styles,
		...filterBaseProps(otherProps, { eventProps: true }),
		children: /* @__PURE__ */ jsxs(DialogTrigger, {
			type: "popover",
			placement: "bottom start",
			containerPadding,
			shouldUpdatePosition,
			shouldFlip: shouldFlip && shouldUpdatePosition,
			isDismissable: true,
			shouldCloseOnInteractOutside: (el) => {
				const menuTriggerEl = el.closest("[data-popover-trigger]");
				if (!menuTriggerEl) return true;
				if (menuTriggerEl === triggerRef?.current) return true;
				return false;
			},
			children: [renderTrigger, (close) => /* @__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: triggerWidth ? { "--overlay-min-width": `${triggerWidth}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: () => close(),
						onOptionClick: (key) => {
							if (selectionMode === "multiple" && isCheckable || key === "__ALL__") close();
						},
						onSelectionChange: (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);
							}
							onSelectionChange?.(selection);
							if (selectionMode === "single") close();
						},
						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