import { A as defaultOperatorNegationMap, D as joinWith, T as objectKeys } from "./utils-nQU7WCM9.mjs";
import { i as isPojo, n as isRuleGroupType } from "./isRuleGroup-DztIOOKa.mjs";
import { n as convertToIC } from "./convertQuery-DAj92cbM.mjs";
import { n as fieldIsValidUtil, r as getFieldsArray, t as prepareRuleGroup } from "./prepareQueryObjects-BBayjIn2.mjs";

//#region src/utils/parseMongoDB/utils.ts
const getRegExStr = (re) => typeof re === "string" ? re : re.source;
const isPrimitive = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean";
const mongoDbToRqbOperatorMap = {
	$eq: "=",
	$ne: "!=",
	$gt: ">",
	$gte: ">=",
	$lt: "<",
	$lte: "<="
};

//#endregion
//#region src/utils/parseMongoDB/parseMongoDB.ts
const emptyRuleGroup = {
	combinator: "and",
	rules: []
};
function parseMongoDB(mongoDbRules, options = {}) {
	const listsAsArrays = !!options.listsAsArrays;
	const fieldsFlat = getFieldsArray(options.fields);
	const getValueSources = options.getValueSources;
	const additionalOperators = options.additionalOperators ?? {};
	const preventOperatorNegation = !!options.preventOperatorNegation;
	const { additionalOperators: _ao, ...otherOptions } = options;
	const fieldIsValid = (fieldName, operator, subordinateFieldName) => fieldIsValidUtil({
		fieldName,
		fieldsFlat,
		operator,
		subordinateFieldName,
		getValueSources
	});
	function processMongoDbQueryBooleanOperator(field, mdbOperator, keyValue) {
		let operator = "=";
		let value = "";
		// istanbul ignore else
		if (mdbOperator === "$eq" || mdbOperator === "$ne" || mdbOperator === "$gt" || mdbOperator === "$gte" || mdbOperator === "$lt" || mdbOperator === "$lte") if (mdbOperator === "$ne" && keyValue === null) {
			if (fieldIsValid(field, "notNull")) return {
				field,
				operator: "notNull",
				value: null
			};
		} else {
			operator = mongoDbToRqbOperatorMap[mdbOperator];
			if (fieldIsValid(field, operator)) return {
				field,
				operator,
				value: keyValue
			};
		}
		else if (mdbOperator === "$regex" && /^[^$^]$|^[^^].*[^$]$/.test(getRegExStr(keyValue))) {
			if (fieldIsValid(field, "contains")) return {
				field,
				operator: "contains",
				value: getRegExStr(keyValue)
			};
		} else if (mdbOperator === "$regex" && /^\^.*[^$]/.test(getRegExStr(keyValue))) {
			if (fieldIsValid(field, "beginsWith")) return {
				field,
				operator: "beginsWith",
				value: getRegExStr(keyValue).replace(/^\^/, "")
			};
		} else if (mdbOperator === "$regex" && /[^^].*\$/.test(getRegExStr(keyValue))) {
			if (fieldIsValid(field, "endsWith")) return {
				field,
				operator: "endsWith",
				value: getRegExStr(keyValue).replace(/\$$/, "")
			};
		} else if (mdbOperator === "$in" && Array.isArray(keyValue)) {
			if (fieldIsValid(field, "in")) {
				value = listsAsArrays ? keyValue : joinWith(keyValue.map((v) => `${v}`), ",");
				return {
					field,
					operator: "in",
					value
				};
			}
		} else if (mdbOperator === "$nin" && Array.isArray(keyValue) && fieldIsValid(field, "notIn")) {
			value = listsAsArrays ? keyValue : joinWith(keyValue.map((v) => `${v}`), ",");
			return {
				field,
				operator: "notIn",
				value
			};
		}
		return false;
	}
	function processMongoDbQueryObjectKey(key, keyValue) {
		let field = "";
		// istanbul ignore else
		if (key === "$and") {
			if (!Array.isArray(keyValue) || keyValue.length === 0 || !keyValue.every((v) => isPojo(v))) return false;
			if (keyValue.length === 2 && keyValue.every((kv) => objectKeys(kv).length === 1)) {
				const [rule1, rule2] = keyValue;
				const [ruleKey1, ruleKey2] = keyValue.map((kv) => objectKeys(kv)[0]);
				if (ruleKey1 === ruleKey2 && isPojo(rule1[ruleKey1]) && objectKeys(rule1[ruleKey1]).length === 1 && isPojo(rule2[ruleKey2]) && objectKeys(rule2[ruleKey2]).length === 1 && ("$gte" in rule1[ruleKey1] && "$lte" in rule2[ruleKey2] && rule2[ruleKey2].$lte >= rule1[ruleKey1].$gte || "$lte" in rule1[ruleKey1] && "$gte" in rule2[ruleKey2] && rule1[ruleKey1].$lte >= rule2[ruleKey2].$gte)) {
					const [val1, val2] = [rule1[ruleKey1].$gte ?? rule1[ruleKey1].$lte, rule2[ruleKey2].$lte ?? rule2[ruleKey2].$gte];
					let value = listsAsArrays ? [val1, val2] : joinWith([val1, val2], ",");
					if (val1 > val2) value = listsAsArrays ? [val2, val1] : joinWith([val2, val1], ",");
					return {
						field: ruleKey1,
						operator: "between",
						value
					};
				}
			}
			const rules = keyValue.map((l) => processMongoDbQueryObject(l)).filter(Boolean);
			return rules.length > 0 ? {
				combinator: "and",
				rules
			} : false;
		} else if (key === "$or") {
			if (!Array.isArray(keyValue) || keyValue.length === 0 || !keyValue.every((v) => isPojo(v))) return false;
			if (keyValue.length === 2 && keyValue.every((kv) => objectKeys(kv).length === 1)) {
				const [rule1, rule2] = keyValue;
				const [ruleKey1, ruleKey2] = keyValue.map((kv) => objectKeys(kv)[0]);
				if (ruleKey1 === ruleKey2 && isPojo(rule1[ruleKey1]) && objectKeys(rule1[ruleKey1]).length === 1 && isPojo(rule2[ruleKey2]) && objectKeys(rule2[ruleKey2]).length === 1 && ("$gt" in rule1[ruleKey1] && "$lt" in rule2[ruleKey2] && rule1[ruleKey1].$gt >= rule2[ruleKey2].$lt || "$lt" in rule1[ruleKey1] && "$gt" in rule2[ruleKey2] && rule2[ruleKey2].$gt >= rule1[ruleKey1].$lt)) {
					const [val1, val2] = [rule1[ruleKey1].$gt ?? rule1[ruleKey1].$lt, rule2[ruleKey2].$lt ?? rule2[ruleKey2].$gt];
					let value = listsAsArrays ? [val1, val2] : `${val1},${val2}`;
					if (val1 > val2) value = listsAsArrays ? [val2, val1] : `${val2},${val1}`;
					return {
						field: ruleKey1,
						operator: "notBetween",
						value
					};
				}
			}
			const rules = keyValue.map((l) => processMongoDbQueryObject(l)).filter(Boolean);
			return rules.length > 0 ? {
				combinator: "or",
				rules
			} : false;
		} else if (key === "$not" && isPojo(keyValue)) {
			const ruleOrGroup = processMongoDbQueryObject(keyValue);
			if (ruleOrGroup) {
				if (isRuleGroupType(ruleOrGroup)) return ruleOrGroup.not ? {
					combinator: "and",
					rules: [ruleOrGroup],
					not: true
				} : {
					...ruleOrGroup,
					not: true
				};
				return preventOperatorNegation ? {
					combinator: "and",
					rules: [ruleOrGroup],
					not: true
				} : {
					...ruleOrGroup,
					operator: defaultOperatorNegationMap[ruleOrGroup.operator]
				};
			}
			return false;
		} else if (key === "$expr") {
			const op = objectKeys(keyValue)[0];
			if (/^\$(eq|gte?|lte?|n?in)$/.test(op) && Array.isArray(keyValue[op]) && keyValue[op].length === 2 && typeof keyValue[op][0] === "string" && keyValue[op][0].startsWith("$")) {
				field = keyValue[op][0].replace(/^\$/, "");
				const val = keyValue[op][1];
				if (typeof val === "string" && val.startsWith("$") || Array.isArray(val) && val.every((v) => typeof v === "string") && val.every((v) => v.startsWith("$"))) {
					const valForProcessing = Array.isArray(val) ? val.map((v) => v.replace(/^\$/, "")) : val.replace(/^\$/, "");
					const tempRule = processMongoDbQueryBooleanOperator(field, op, valForProcessing);
					if (tempRule) {
						if (typeof tempRule.value === "string" && !fieldIsValid(field, tempRule.operator, tempRule.value)) return false;
						return {
							...tempRule,
							valueSource: "field"
						};
					}
				}
				return processMongoDbQueryBooleanOperator(field, op, keyValue[op][1]);
			}
		} else if (/^[^$]/.test(key)) {
			field = key;
			if (isPrimitive(keyValue)) {
				if (fieldIsValid(field, "=")) return {
					field,
					operator: "=",
					value: keyValue
				};
			} else if (keyValue === null) {
				if (fieldIsValid(field, "null")) return {
					field,
					operator: "null",
					value: keyValue
				};
			} else if (isPojo(keyValue)) {
				let betweenRule = false;
				let notRule = false;
				const allOps = [
					"eq",
					"ne",
					"gte?",
					"lte?",
					"n?in",
					"regex",
					"not",
					...objectKeys(additionalOperators).map((o) => o.replace(/^\$/, ""))
				];
				const acceptedOpsRegExp = /* @__PURE__ */ new RegExp(`^\\$(${allOps.join("|")})$`);
				const operators = objectKeys(keyValue).filter((o) => acceptedOpsRegExp.test(o)).sort();
				if (operators.length === 0) return false;
				if ("$not" in keyValue && isPojo(keyValue.$not)) {
					const invertedNotRule = processMongoDbQueryObject({ [field]: keyValue.$not });
					if (invertedNotRule) if (isRuleGroupType(invertedNotRule)) notRule = {
						...invertedNotRule,
						not: true
					};
					else notRule = preventOperatorNegation ? {
						combinator: "and",
						rules: [invertedNotRule],
						not: true
					} : {
						...invertedNotRule,
						operator: defaultOperatorNegationMap[invertedNotRule.operator]
					};
				}
				if ("$gte" in keyValue && "$lte" in keyValue) betweenRule = {
					field,
					operator: "between",
					value: listsAsArrays ? [keyValue.$gte, keyValue.$lte] : `${keyValue.$gte},${keyValue.$lte}`
				};
				const rules = operators.filter((op) => !(notRule && op === "$not")).filter((op) => !(betweenRule && (op === "$gte" || op === "$lte"))).map((op) => op in additionalOperators && typeof additionalOperators[op] === "function" ? additionalOperators[op](field, op, keyValue[op], otherOptions) : processMongoDbQueryBooleanOperator(field, op, keyValue[op])).filter(Boolean);
				if (notRule) rules.unshift(notRule);
				if (betweenRule) rules.unshift(betweenRule);
				if (rules.length === 0) return false;
				if (rules.length === 1) return rules[0];
				return {
					combinator: "and",
					rules
				};
			}
		}
		return false;
	}
	function processMongoDbQueryObject(mongoDbQueryObject) {
		const rules = objectKeys(mongoDbQueryObject).map((k) => processMongoDbQueryObjectKey(k, mongoDbQueryObject[k])).filter(Boolean);
		return rules.length === 1 ? rules[0] : rules.length > 1 ? {
			combinator: "and",
			rules
		} : false;
	}
	const prepare = options.generateIDs ? prepareRuleGroup : (g) => g;
	let mongoDbPOJO = mongoDbRules;
	if (typeof mongoDbRules === "string") try {
		mongoDbPOJO = JSON.parse(mongoDbRules);
	} catch {
		return prepare(emptyRuleGroup);
	}
	if (!isPojo(mongoDbPOJO)) return prepare(emptyRuleGroup);
	const result = processMongoDbQueryObject(mongoDbPOJO);
	const finalQuery = result ? isRuleGroupType(result) ? result : {
		combinator: "and",
		rules: [result]
	} : emptyRuleGroup;
	return prepare(options.independentCombinators ? convertToIC(finalQuery) : finalQuery);
}

//#endregion
export { parseMongoDB };
//# sourceMappingURL=parseMongoDB.mjs.map