const require_runtime = require("../../_virtual/_rolldown/runtime.js");
const require_objectSpread2 = require("../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js");
const require_asyncToGenerator = require("../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js");
const require_useEngineContext = require("../../hooks/useEngineContext.js");
const require_useThemeTokens = require("../../hooks/useThemeTokens.js");
const require_locales = require("./locales.js");
const require_Selector = require("./Selector.js");
const require_index = require("./utils/index.js");
const require_IntersectionObserver = require("./components/IntersectionObserver.js");
const require_CategorySkeleton = require("../../plus/productSelect/CategoryTabs/CategorySkeleton.js");
const require_utils = require("../../plus/productSelect/utils.js");
const require_index$1 = require("../../plus/productSelect/CategoryTabs/index.js");
let react = require("react");
react = require_runtime.__toESM(react);
let _pisell_utils = require("@pisell/utils");
let lodash = require("lodash");
let classnames = require("classnames");
classnames = require_runtime.__toESM(classnames);
require("./selectorGroup.less");
//#region src/pro/Selector/SelectorGroup.tsx
const DEFAULT_DATASOURCE = [];
const SelectorGroup = (0, react.forwardRef)((props, ref) => {
	var _context$appHelper, _props$tabProps2;
	const context = require_useEngineContext.default();
	_pisell_utils.locales.init(require_locales.default, (context === null || context === void 0 || (_context$appHelper = context.appHelper) === null || _context$appHelper === void 0 || (_context$appHelper = _context$appHelper.utils) === null || _context$appHelper === void 0 || (_context$appHelper = _context$appHelper.storage) === null || _context$appHelper === void 0 ? void 0 : _context$appHelper.get("umi_locale")) || "en");
	const { linkageRules, allowedValuesPolicy = "strict", preserve: preserveDefault = false, style } = props;
	const { colorPrimary, colorPrimaryBg } = require_useThemeTokens.default(props.theme);
	const [activeIndex, setActiveIndex] = (0, react.useState)(-1);
	const isManualChangeIndexRef = (0, react.useRef)(false);
	const containerRef = (0, react.useRef)(null);
	const _uniqueId = (0, react.useRef)(require_index.generateSimpleUUID().substring(0, 8)).current;
	const groupRefs = (0, react.useRef)({});
	const reducer = (state, action) => {
		switch (action.type) {
			case "commit": return action.payload;
			case "patch": return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, state), action.payload);
			default: return state;
		}
	};
	const [state, dispatch] = (0, react.useReducer)(reducer, {
		values: {},
		visibleGroups: {},
		optionEffects: {}
	});
	(0, react.useEffect)(() => {
		var _value;
		const initial = ((_value = props === null || props === void 0 ? void 0 : props.value) !== null && _value !== void 0 ? _value : props === null || props === void 0 ? void 0 : props.defaultValue) || {};
		if (initial && typeof initial === "object") applyValues(require_objectSpread2._objectSpread2({}, initial));
	}, []);
	const normalizedRules = (0, react.useMemo)(() => require_index.normalizeRules(linkageRules), [(0, react.useMemo)(() => {
		try {
			return JSON.stringify(linkageRules !== null && linkageRules !== void 0 ? linkageRules : null);
		} catch (_unused) {
			return String(linkageRules);
		}
	}, [linkageRules])]);
	const autoHiddenGroups = (0, react.useMemo)(() => require_index.computeAutoHiddenGroups(normalizedRules), [normalizedRules]);
	const dataSource = (0, react.useMemo)(() => {
		if (Array.isArray(props.dataSource)) return props.dataSource.filter((item) => !!item && item.id !== void 0);
		return DEFAULT_DATASOURCE;
	}, [props.dataSource]);
	const stateRef = (0, react.useRef)(state);
	const dataSourceRef = (0, react.useRef)(dataSource);
	(0, react.useEffect)(() => {
		stateRef.current = state;
	}, [state]);
	(0, react.useEffect)(() => {
		dataSourceRef.current = dataSource;
	}, [dataSource]);
	const hasInitializedVisibilityRef = (0, react.useRef)(false);
	(0, react.useEffect)(() => {
		if (!hasInitializedVisibilityRef.current && (!state.visibleGroups || Object.keys(state.visibleGroups).length === 0)) {
			const initVisible = {};
			(dataSource || []).forEach((group) => {
				var _group$id;
				const gid = String((_group$id = group.id) !== null && _group$id !== void 0 ? _group$id : "");
				initVisible[gid] = autoHiddenGroups.has(gid) ? false : true;
			});
			hasInitializedVisibilityRef.current = true;
			dispatch({
				type: "patch",
				payload: { visibleGroups: initVisible }
			});
		}
	}, [dataSource, autoHiddenGroups]);
	const lastEmittedRef = (0, react.useRef)(null);
	const applyValues = (0, react.useCallback)((nextValues, visibleOverride) => {
		const maskValues = (vals, visibleMap) => {
			const out = require_objectSpread2._objectSpread2({}, vals || {});
			(dataSource || []).forEach((group) => {
				var _group$id2;
				const gid = String((_group$id2 = group.id) !== null && _group$id2 !== void 0 ? _group$id2 : "");
				const preserve = typeof group.preserve === "boolean" ? group.preserve : preserveDefault;
				if (visibleMap[gid] === false && preserve === false) out[gid] = void 0;
			});
			return out;
		};
		const { visibleGroups: newVisible, optionEffects: newEffects } = require_index.computeEffects(dataSource, normalizedRules, maskValues(nextValues, visibleOverride || state.visibleGroups));
		let finalValues = nextValues;
		let finalVisible = newVisible;
		let finalEffects = newEffects;
		if (allowedValuesPolicy === "strict") {
			const pruned = require_index.pruneValuesByAllowOnly(nextValues, newEffects);
			if (!(0, lodash.isEqual)(pruned, nextValues)) {
				finalValues = pruned;
				const recomputed = require_index.computeEffects(dataSource, normalizedRules, maskValues(finalValues, newVisible));
				finalVisible = recomputed.visibleGroups;
				finalEffects = recomputed.optionEffects;
			}
		}
		if (!((0, lodash.isEqual)(state.values, finalValues) && (0, lodash.isEqual)(state.visibleGroups, finalVisible) && (0, lodash.isEqual)(state.optionEffects, finalEffects))) dispatch({
			type: "commit",
			payload: {
				values: require_objectSpread2._objectSpread2({}, finalValues || {}),
				visibleGroups: finalVisible,
				optionEffects: finalEffects
			}
		});
		if (typeof (props === null || props === void 0 ? void 0 : props.onChange) === "function") {
			const out = {};
			(dataSource || []).forEach((group) => {
				var _group$id3;
				const gid = String((_group$id3 = group.id) !== null && _group$id3 !== void 0 ? _group$id3 : "");
				const preserve = typeof group.preserve === "boolean" ? group.preserve : preserveDefault;
				if (finalVisible[gid] === false && preserve === false) return;
				const v = finalValues[gid];
				if (v !== void 0) out[gid] = v;
			});
			if (!(0, lodash.isEqual)(lastEmittedRef.current, out)) {
				lastEmittedRef.current = out;
				props.onChange(out);
			}
		}
	}, [
		dataSource,
		normalizedRules,
		allowedValuesPolicy,
		preserveDefault,
		state.visibleGroups,
		state.values,
		state.optionEffects,
		props === null || props === void 0 ? void 0 : props.onChange
	]);
	const getValuesInternal = (0, react.useCallback)((includeHidden, visibleOverride) => {
		if (includeHidden) return require_objectSpread2._objectSpread2({}, state.values || {});
		const visibleMap = visibleOverride || state.visibleGroups;
		const result = {};
		(dataSource || []).forEach((group) => {
			var _group$id4;
			const gid = String((_group$id4 = group.id) !== null && _group$id4 !== void 0 ? _group$id4 : "");
			const preserve = typeof group.preserve === "boolean" ? group.preserve : preserveDefault;
			if (visibleMap[gid] === false && preserve === false) return;
			const v = state.values[gid];
			if (v !== void 0) result[gid] = v;
		});
		return result;
	}, [
		dataSource,
		state.visibleGroups,
		preserveDefault,
		state.values
	]);
	(0, react.useEffect)(() => {
		applyValues(require_objectSpread2._objectSpread2({}, state.values || {}));
	}, [
		dataSource,
		normalizedRules,
		allowedValuesPolicy
	]);
	(0, react.useEffect)(() => {
		const external = props === null || props === void 0 ? void 0 : props.value;
		if (external && typeof external === "object") {
			const prev = state.values || {};
			const next = external || {};
			if (!(0, lodash.isEqual)(prev, next)) applyValues(require_objectSpread2._objectSpread2({}, next));
		}
	}, [props === null || props === void 0 ? void 0 : props.value]);
	const handleGroupChange = (0, react.useCallback)((groupId, v) => {
		applyValues(require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, state.values || {}), {}, { [groupId]: v }));
	}, [state.values, applyValues]);
	const _categories = (0, react.useMemo)(() => {
		return dataSource.filter((item) => {
			var _item$id;
			return state.visibleGroups[String((_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : "")] !== false;
		}).map((item) => {
			var _item$id2;
			return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, item), {}, {
				key: String((_item$id2 = item.id) !== null && _item$id2 !== void 0 ? _item$id2 : ""),
				label: item.title
			});
		});
	}, [dataSource, state.visibleGroups]);
	const debounceIndicator = (0, react.useCallback)((delay) => {
		isManualChangeIndexRef.current = true;
		const timeoutId = setTimeout(() => {
			isManualChangeIndexRef.current = false;
		}, delay);
		return () => clearTimeout(timeoutId);
	}, []);
	const switchCategory = (0, react.useCallback)((key) => {
		setActiveIndex(_categories.findIndex((item) => item.key === key));
		debounceIndicator(300);
		const categoryIndex = dataSource.findIndex((item) => String(item.id) === key);
		let _scrollParent = null;
		if (typeof props.customScrollParent === "string") _scrollParent = document.querySelector(props.customScrollParent);
		else _scrollParent = props.customScrollParent || containerRef.current;
		if (!_scrollParent || !containerRef.current) return;
		const target = document.getElementById(`pisell-pro-selector-${key}`);
		if (!target) return;
		const batchSelectorWrapper = document.querySelector(`.pisell-batch-selector-${_uniqueId}`);
		const tabsWrapper = document.getElementById(`pisell-batch-selector-${_uniqueId}_tabs`);
		const tabsHeight = (tabsWrapper === null || tabsWrapper === void 0 ? void 0 : tabsWrapper.offsetHeight) || 0;
		const extraOffset = 0;
		if (categoryIndex === 0) {
			if (batchSelectorWrapper) {
				const wrapperOffsetTop = require_utils.getOffsetTopRelativeToScrollContainer(batchSelectorWrapper, _scrollParent);
				_scrollParent.scrollTop = wrapperOffsetTop - extraOffset;
			}
			return;
		} else {
			const listOffsetTop = require_utils.getOffsetTopRelativeToScrollContainer(target, _scrollParent);
			_scrollParent.scrollTop = listOffsetTop - tabsHeight - extraOffset;
		}
	}, [
		_categories,
		dataSource,
		debounceIndicator,
		props.customScrollParent,
		_uniqueId
	]);
	(0, react.useImperativeHandle)(ref, () => ({
		getValues: (includeHidden) => getValuesInternal(includeHidden),
		setValues: (values) => {
			applyValues(require_objectSpread2._objectSpread2({}, values || {}));
		},
		validate: function() {
			var _ref2 = require_asyncToGenerator._asyncToGenerator(function* () {
				const currentDataSource = dataSourceRef.current || [];
				const currentVisibleGroups = stateRef.current.visibleGroups;
				const validateGroup = function() {
					var _ref = require_asyncToGenerator._asyncToGenerator(function* (ds) {
						var _ds$id;
						const gid = String((_ds$id = ds.id) !== null && _ds$id !== void 0 ? _ds$id : "");
						const successResult = {
							gid,
							ok: true,
							errors: []
						};
						if (currentVisibleGroups[gid] === false) return successResult;
						const inst = groupRefs.current[gid];
						if (!(inst === null || inst === void 0 ? void 0 : inst.validate)) return successResult;
						try {
							yield inst.validate();
							return successResult;
						} catch (errors) {
							return {
								gid,
								ok: false,
								errors: Array.isArray(errors) ? errors : errors ? [errors] : []
							};
						}
					});
					return function validateGroup(_x) {
						return _ref.apply(this, arguments);
					};
				}();
				const results = yield Promise.all(currentDataSource.map(validateGroup));
				const errorsByGroup = {};
				let firstErrorGID;
				for (const result of results) if (!result.ok && result.errors.length > 0) {
					errorsByGroup[result.gid] = result.errors;
					if (!firstErrorGID) firstErrorGID = result.gid;
				}
				if (Object.keys(errorsByGroup).length > 0) {
					if (props.scrollToFirstError !== false && firstErrorGID) switchCategory(firstErrorGID);
					return Promise.reject(errorsByGroup);
				}
				return Promise.resolve({});
			});
			return function validate() {
				return _ref2.apply(this, arguments);
			};
		}(),
		reset: () => {
			applyValues(require_objectSpread2._objectSpread2({}, (props === null || props === void 0 ? void 0 : props.defaultValue) || {}));
			Object.keys(groupRefs.current).forEach((gid) => {
				var _inst$reset;
				const inst = groupRefs.current[gid];
				inst === null || inst === void 0 || (_inst$reset = inst.reset) === null || _inst$reset === void 0 || _inst$reset.call(inst);
			});
		},
		clear: () => {
			applyValues({});
			Object.keys(groupRefs.current).forEach((gid) => {
				var _inst$clear;
				const inst = groupRefs.current[gid];
				inst === null || inst === void 0 || (_inst$clear = inst.clear) === null || _inst$clear === void 0 || _inst$clear.call(inst);
			});
		}
	}), [
		getValuesInternal,
		applyValues,
		props.scrollToFirstError,
		props === null || props === void 0 ? void 0 : props.defaultValue,
		switchCategory
	]);
	const patchedDataSourceMap = (0, react.useMemo)(() => {
		const map = {};
		(dataSource || []).forEach((group) => {
			var _group$id5, _group$fieldNames;
			const gid = String((_group$id5 = group.id) !== null && _group$id5 !== void 0 ? _group$id5 : "");
			const fieldValue = (group === null || group === void 0 || (_group$fieldNames = group.fieldNames) === null || _group$fieldNames === void 0 ? void 0 : _group$fieldNames.value) || "value";
			const effects = state.optionEffects[gid];
			map[gid] = (Array.isArray(group.dataSource) ? group.dataSource : []).map((opt) => {
				const val = opt[fieldValue];
				return (effects === null || effects === void 0 ? void 0 : effects.allowOnly) && !effects.allowOnly.has(val) ? require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, opt), {}, { disabled: true }) : opt;
			});
		});
		return map;
	}, [dataSource, state.optionEffects]);
	const validationMaps = (0, react.useMemo)(() => {
		const titleTipMap = {};
		const customValidatorMap = {};
		(dataSource || []).forEach((group) => {
			var _group$id6, _state$optionEffects$;
			const gid = String((_group$id6 = group.id) !== null && _group$id6 !== void 0 ? _group$id6 : "");
			const req = (_state$optionEffects$ = state.optionEffects[gid]) === null || _state$optionEffects$ === void 0 ? void 0 : _state$optionEffects$.requireOneOf;
			if (req) {
				var _state$values;
				const currentSel = require_index.getSelectedSet((_state$values = state.values) === null || _state$values === void 0 ? void 0 : _state$values[gid]);
				titleTipMap[gid] = [...req.values].some((v) => currentSel.has(v)) ? void 0 : req.tip || _pisell_utils.locales.getText("pisell2.pro.selector.validate.requireOneOf-msg");
				customValidatorMap[gid] = function() {
					var _ref3 = require_asyncToGenerator._asyncToGenerator(function* (value) {
						const sel = require_index.getSelectedSet(value);
						if (![...req.values].some((v) => sel.has(v))) throw {
							type: "requireOneOf",
							message: req.message || _pisell_utils.locales.getText("pisell2.pro.selector.validate.requireOneOf-msg")
						};
					});
					return function(_x2) {
						return _ref3.apply(this, arguments);
					};
				}();
			} else {
				titleTipMap[gid] = void 0;
				customValidatorMap[gid] = void 0;
			}
		});
		return {
			titleTipMap,
			customValidatorMap
		};
	}, [
		dataSource,
		state.optionEffects,
		state.values
	]);
	const activeKey = (0, react.useMemo)(() => {
		var _categories$activeInd;
		return (_categories$activeInd = _categories[activeIndex]) === null || _categories$activeInd === void 0 ? void 0 : _categories$activeInd.key;
	}, [activeIndex, _categories]);
	const renderTabs = () => {
		var _props$tabProps;
		if (((_props$tabProps = props.tabProps) === null || _props$tabProps === void 0 ? void 0 : _props$tabProps.visible) === false) return null;
		if ((props.dataSource || []).length <= 1) return null;
		return /* @__PURE__ */ react.default.createElement(require_index$1.default, {
			activeKey: activeKey ? String(activeKey) : "",
			items: _categories,
			onChange: switchCategory,
			loading: props.loading,
			skeleton: /* @__PURE__ */ react.default.createElement(require_CategorySkeleton.default, null),
			id: `pisell-batch-selector-${_uniqueId}_tabs`
		});
	};
	const _content = (0, react.useMemo)(() => {
		return /* @__PURE__ */ react.default.createElement("div", { className: `pisell-batch-selector__content` }, dataSource.filter((item) => {
			var _item$id3;
			return state.visibleGroups[String((_item$id3 = item.id) !== null && _item$id3 !== void 0 ? _item$id3 : "")] !== false;
		}).map((item, index) => {
			var _item$id4, _state$values2, _headerProps$tip$visi, _headerProps$tip;
			const gid = String((_item$id4 = item.id) !== null && _item$id4 !== void 0 ? _item$id4 : "");
			const headerProps = item.headerProps || item.titleProps || {};
			return /* @__PURE__ */ react.default.createElement(require_IntersectionObserver.IntersectionItem, {
				key: gid,
				index
			}, /* @__PURE__ */ react.default.createElement(require_Selector.default, require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, item), {}, {
				ref: (el) => {
					if (el) groupRefs.current[gid] = el;
					else delete groupRefs.current[gid];
				},
				value: (_state$values2 = state.values) === null || _state$values2 === void 0 ? void 0 : _state$values2[gid],
				onChange: (v) => {
					var _item$onChange;
					handleGroupChange(gid, v);
					(_item$onChange = item.onChange) === null || _item$onChange === void 0 || _item$onChange.call(item, v);
				},
				ruleConfig: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, item.ruleConfig), {}, { customValidator: validationMaps.customValidatorMap[gid] }),
				dataSource: patchedDataSourceMap[gid],
				headerProps: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, headerProps), validationMaps.titleTipMap[gid] === void 0 ? {} : { tip: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, (headerProps === null || headerProps === void 0 ? void 0 : headerProps.tip) || {}), {}, {
					text: validationMaps.titleTipMap[gid],
					visible: (_headerProps$tip$visi = headerProps === null || headerProps === void 0 || (_headerProps$tip = headerProps.tip) === null || _headerProps$tip === void 0 ? void 0 : _headerProps$tip.visible) !== null && _headerProps$tip$visi !== void 0 ? _headerProps$tip$visi : true
				}) })
			})));
		}));
	}, [
		dataSource,
		state.visibleGroups,
		state.values,
		patchedDataSourceMap,
		validationMaps,
		groupRefs,
		handleGroupChange
	]);
	return /* @__PURE__ */ react.default.createElement("div", {
		className: (0, classnames.default)("pisell-batch-selector", `pisell-batch-selector-${_uniqueId}`),
		ref: containerRef,
		style: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, style || {}), {}, {
			["--color-primary"]: colorPrimary,
			["--color-primary-bg"]: colorPrimaryBg
		})
	}, renderTabs(), /* @__PURE__ */ react.default.createElement(require_IntersectionObserver.default, {
		rootMargin: "-70px 0px 0px 0px",
		disabled: ((_props$tabProps2 = props.tabProps) === null || _props$tabProps2 === void 0 ? void 0 : _props$tabProps2.visible) === false,
		onFirstVisibleIndexChange: (index) => {
			if (!isManualChangeIndexRef.current) {
				if (index === -1 || index === activeIndex) return;
				setActiveIndex(index);
			}
		}
	}, _content));
});
//#endregion
exports.default = SelectorGroup;
