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");
let react = require("react");
let _pisell_utils = require("@pisell/utils");
let ahooks = require("ahooks");
//#region src/pro/Selector/hooks/useSelectionController.ts
function useSelectionController(props) {
	const { dataSource = [], ruleConfig, fieldNames, mode = "single", valueType = "primitive" } = props || {};
	const [values, setValues] = (0, ahooks.useControllableValue)(props);
	const valuesRef = (0, react.useRef)(values);
	valuesRef.current = values;
	const [errors, setErrors] = (0, react.useState)([]);
	const [validated, setValidated] = (0, react.useState)(false);
	const normalizedOptions = (0, react.useMemo)(() => {
		return dataSource.map((option) => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, option), {}, {
			_key: option[(fieldNames === null || fieldNames === void 0 ? void 0 : fieldNames.value) || "value"],
			_label: option[(fieldNames === null || fieldNames === void 0 ? void 0 : fieldNames.label) || "label"],
			_cover: option[(fieldNames === null || fieldNames === void 0 ? void 0 : fieldNames.cover) || "cover"]
		}));
	}, [dataSource, fieldNames]);
	const mutexGroups = (0, react.useMemo)(() => {
		const groups = [];
		const m = ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.mutex;
		if (Array.isArray(m)) m.forEach((g) => {
			if (Array.isArray(g) && g.length > 0) groups.push(g);
		});
		return groups;
	}, [ruleConfig]);
	const mutexIndex = (0, react.useMemo)(() => {
		const map = /* @__PURE__ */ new Map();
		mutexGroups.forEach((group, idx) => {
			group.forEach((k) => {
				const arr = map.get(k) || [];
				arr.push(idx);
				map.set(k, arr);
			});
		});
		return map;
	}, [mutexGroups]);
	const normalizedValues = (0, react.useMemo)(() => {
		if (!values) return [];
		if (Array.isArray(values)) return values.map((item) => {
			if (typeof item === "object" && item !== null) return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, item), {}, {
				value: item.value,
				quantity: item.quantity || 1
			});
			return {
				value: item,
				quantity: 1
			};
		});
		if (typeof values === "object" && values !== null) {
			const objValue = values;
			return [require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, objValue), {}, {
				value: objValue.value,
				quantity: objValue.quantity || 1
			})];
		}
		return [{
			value: values,
			quantity: 1
		}];
	}, [values]);
	const quantityInfo = (0, react.useMemo)(() => {
		const selectedCount = normalizedValues.reduce((sum, item) => sum + (item.quantity || 0), 0);
		const showQuantity = (Array.isArray(dataSource) ? dataSource : dataSource || []).some((opt) => {
			var _opt$ruleConfig, _opt$ruleConfig2;
			return typeof (opt === null || opt === void 0 || (_opt$ruleConfig = opt.ruleConfig) === null || _opt$ruleConfig === void 0 ? void 0 : _opt$ruleConfig.max) === "number" && opt.ruleConfig.max > 1 || typeof (opt === null || opt === void 0 || (_opt$ruleConfig2 = opt.ruleConfig) === null || _opt$ruleConfig2 === void 0 ? void 0 : _opt$ruleConfig2.min) === "number" && opt.ruleConfig.min > 1;
		});
		return {
			maxReached: typeof (ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.max) === "number" && ruleConfig.max > 0 && selectedCount >= ruleConfig.max,
			showQuantity,
			remainingCount: typeof (ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.max) === "number" && ruleConfig.max > 0 ? Math.max(0, ruleConfig.max - selectedCount) : Infinity,
			selectedCount
		};
	}, [
		normalizedValues,
		dataSource,
		ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.max
	]);
	const getOptionState = (0, react.useCallback)((optionKey) => {
		const found = normalizedValues.find((item) => item.value === optionKey);
		return {
			selected: !!found,
			quantity: (found === null || found === void 0 ? void 0 : found.quantity) || 0
		};
	}, [normalizedValues]);
	const options = (0, react.useMemo)(() => {
		return normalizedOptions.map((option) => {
			const state = getOptionState(option._key);
			const disabled = quantityInfo.maxReached && !(mode === "single" && (ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.max) === 1) && !state.selected;
			return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, option), {}, {
				selected: state.selected,
				quantity: state.quantity,
				disabled: option.disabled || disabled
			});
		});
	}, [
		normalizedOptions,
		getOptionState,
		quantityInfo.maxReached,
		mode,
		ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.max
	]);
	const validate = function() {
		var _ref = require_asyncToGenerator._asyncToGenerator(function* () {
			const errors = [];
			const { required, min, max, customValidator } = ruleConfig || {};
			const values = valuesRef.current;
			let currentNormalizedValues = [];
			if (values) if (Array.isArray(values)) currentNormalizedValues = values.map((item) => {
				if (typeof item === "object" && item !== null) return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, item), {}, {
					value: item.value,
					quantity: item.quantity || 1
				});
				return {
					value: item,
					quantity: 1
				};
			});
			else if (typeof values === "object" && values !== null) {
				const objValue = values;
				currentNormalizedValues = [require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, objValue), {}, {
					value: objValue.value,
					quantity: objValue.quantity || 1
				})];
			} else currentNormalizedValues = [{
				value: values,
				quantity: 1
			}];
			const totalQuantity = currentNormalizedValues.reduce((sum, item) => sum + (item.quantity || 0), 0);
			if (required && totalQuantity < 1) errors.push({
				type: "required",
				message: _pisell_utils.locales.getText("pisell2.pro.selector.validate.required-msg")
			});
			if (typeof min === "number" && totalQuantity < min) errors.push({
				type: "min",
				message: _pisell_utils.locales.getText("pisell2.pro.selector.validate.min-selection")(min)
			});
			if (typeof max === "number" && totalQuantity > max) errors.push({
				type: "max",
				message: _pisell_utils.locales.getText("pisell2.pro.selector.validate.max-selection")(max)
			});
			options.forEach((option) => {
				var _option$ruleConfig, _option$ruleConfig2;
				const _optionVal = currentNormalizedValues.find((item) => item.value === option._key);
				const quantity = (_optionVal === null || _optionVal === void 0 ? void 0 : _optionVal.quantity) || 0;
				const { _label } = option;
				const _min = option === null || option === void 0 || (_option$ruleConfig = option.ruleConfig) === null || _option$ruleConfig === void 0 ? void 0 : _option$ruleConfig.min;
				const _max = option === null || option === void 0 || (_option$ruleConfig2 = option.ruleConfig) === null || _option$ruleConfig2 === void 0 ? void 0 : _option$ruleConfig2.max;
				if (typeof _min === "number" && quantity < _min) errors.push({
					type: "optionMin",
					message: _pisell_utils.locales.getText("pisell2.pro.selector.validate.min-selection")(_min, _label),
					_key: option._key
				});
				if (typeof _max === "number" && quantity > _max) errors.push({
					type: "optionMax",
					message: _pisell_utils.locales.getText("pisell2.pro.selector.validate.max-selection")(_max, _label),
					_key: option._key
				});
			});
			if (mutexGroups.length > 0) {
				const selectedKeys = (Array.isArray(values) ? values : values ? [values] : []).map((v) => typeof v === "object" && v !== null ? v.value : v);
				mutexGroups.forEach((group) => {
					if (selectedKeys.filter((k) => group.includes(k)).length > 1) errors.push({
						type: "mutex",
						message: "Only one option can be selected in the same mutex group"
					});
				});
			}
			if (typeof customValidator === "function") try {
				yield customValidator(values);
			} catch (e) {
				const type = (e === null || e === void 0 ? void 0 : e.type) || "custom";
				const message = (e === null || e === void 0 ? void 0 : e.message) || "Validation failed";
				errors.push({
					type,
					message
				});
			}
			setErrors(errors);
			setValidated(true);
			return errors.length === 0 ? Promise.resolve() : Promise.reject(errors);
		});
		return function validate() {
			return _ref.apply(this, arguments);
		};
	}();
	const buildOutputValue = (0, react.useCallback)((newNormalizedValues) => {
		if (newNormalizedValues.length === 0) return mode === "single" ? void 0 : [];
		if (mode === "single") {
			const item = newNormalizedValues[0];
			if (valueType === "primitive") return item.value;
			return require_objectSpread2._objectSpread2({}, item);
		}
		if (valueType === "primitive") return newNormalizedValues.map((item) => item.value);
		return newNormalizedValues.map((item) => {
			return require_objectSpread2._objectSpread2({}, item);
		});
	}, [
		mode,
		valueType,
		quantityInfo.showQuantity
	]);
	const _onChange = (0, react.useCallback)((optionKey, data) => {
		let newNormalizedValues = [...normalizedValues];
		const existingIndex = newNormalizedValues.findIndex((item) => item.value === optionKey);
		if ((data === null || data === void 0 ? void 0 : data.quantity) !== void 0 && data.quantity <= 0) {
			if (existingIndex >= 0) newNormalizedValues.splice(existingIndex, 1);
		} else {
			if (existingIndex >= 0) newNormalizedValues[existingIndex] = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, newNormalizedValues[existingIndex]), data);
			else {
				const newItem = require_objectSpread2._objectSpread2({
					value: optionKey,
					quantity: data.quantity || 1
				}, data);
				if (mode === "single") newNormalizedValues = [newItem];
				else newNormalizedValues.push(newItem);
			}
			const groupIdxList = mutexIndex.get(optionKey) || [];
			if (groupIdxList.length > 0) {
				const keepKey = optionKey;
				const toRemove = /* @__PURE__ */ new Set();
				groupIdxList.forEach((gi) => {
					(mutexGroups[gi] || []).forEach((k) => {
						if (k !== keepKey) toRemove.add(k);
					});
				});
				if (toRemove.size > 0) newNormalizedValues = newNormalizedValues.filter((item) => !toRemove.has(item.value));
			}
		}
		const outputValue = buildOutputValue(newNormalizedValues);
		setValues(outputValue);
		valuesRef.current = outputValue;
		if (ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.autoValidate) try {
			validate();
		} catch (error) {}
	}, [
		normalizedValues,
		mode,
		buildOutputValue,
		setValues,
		mutexIndex,
		mutexGroups,
		ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.autoValidate
	]);
	const clear = (0, react.useCallback)(() => {
		setValues(mode === "single" ? void 0 : []);
		setErrors([]);
	}, [
		mode,
		setValues,
		setErrors
	]);
	const actions = {
		toggle: (optionKey) => {
			_onChange(optionKey, { quantity: getOptionState(optionKey).selected ? 0 : 1 });
		},
		update: (optionKey, payload) => _onChange(optionKey, payload),
		setValue: (value) => setValues(value),
		clear,
		validate,
		reset: (0, react.useCallback)(() => {
			if (props && props.defaultValue !== void 0) setValues(props.defaultValue);
			else clear();
			setErrors([]);
		}, [
			props,
			clear,
			setValues,
			setErrors
		])
	};
	return {
		state: {
			errors,
			validated,
			values,
			options,
			quantityInfo
		},
		actions
	};
}
//#endregion
exports.default = useSelectionController;
