import { t as isRuleGroup } from "./isRuleGroup-DztIOOKa.mjs";
import { n as fieldIsValidUtil, r as getFieldsArray, t as prepareRuleGroup } from "./prepareQueryObjects-BBayjIn2.mjs";
import jsonata from "jsonata";

//#region src/utils/parseJSONata/utils.ts
const isJSONataExprNode = (expr) => {
	return expr && typeof expr === "object" && typeof expr.type === "string";
};
const isJSONataBinaryNode = (expr) => isJSONataExprNode(expr) && expr.type === "binary";
const isJSONataPath = (expr) => isJSONataExprNode(expr) && expr.type === "path" && Array.isArray(expr.steps) && expr.steps.length > 0 && isJSONataExprNode(expr.steps[0]);
const isJSONataName = (expr) => isJSONataExprNode(expr) && expr.type === "name" && typeof expr.value === "string" && expr.value.length > 0;
const isJSONataIdentifier = (expr) => isJSONataPath(expr) && expr.steps.every((v) => isJSONataName(v));
const isJSONataBlock = (expr) => isJSONataExprNode(expr) && expr.type === "block" && Array.isArray(expr.expressions) && expr.expressions.length > 0 && isJSONataExprNode(expr.expressions[0]);
const isJSONataString = (expr) => isJSONataExprNode(expr) && expr.type === "string" && typeof expr.value === "string";
const isJSONataNumber = (expr) => isJSONataExprNode(expr) && expr.type === "number" && typeof expr.value === "number";
const isJSONataBoolean = (expr) => isJSONataExprNode(expr) && expr.type === "value" && typeof expr.value === "boolean";
const isJSONataNull = (expr) => isJSONataExprNode(expr) && expr.type === "value" && expr.value === null;
const isJSONataRegex = (expr) => isJSONataExprNode(expr) && expr.type === "regex" && expr.value instanceof RegExp;
const isJSONataAnd = (expr) => isJSONataBinaryNode(expr) && expr.value === "and";
const isJSONataOr = (expr) => isJSONataBinaryNode(expr) && expr.value === "or";
const isJSONataEqual = (expr) => isJSONataBinaryNode(expr) && expr.value === "=";
const isJSONataNotEqual = (expr) => isJSONataBinaryNode(expr) && expr.value === "!=";
const isJSONataGreaterThan = (expr) => isJSONataBinaryNode(expr) && expr.value === ">";
const isJSONataGreaterThanOrEqual = (expr) => isJSONataBinaryNode(expr) && expr.value === ">=";
const isJSONataLessThan = (expr) => isJSONataBinaryNode(expr) && expr.value === "<";
const isJSONataLessThanOrEqual = (expr) => isJSONataBinaryNode(expr) && expr.value === "<=";
const isJSONataIn = (expr) => isJSONataBinaryNode(expr) && expr.value === "in" && isJSONataPath(expr.lhs) && isJSONataList(expr.rhs);
const isJSONataNot = (expr) => isJSONataExprNode(expr) && expr.type === "function" && expr.value === "(" && Array.isArray(expr.arguments) && isJSONataExprNode(expr.arguments[0]) && isJSONataExprNode(expr.procedure) && expr.procedure.value === "not" && expr.procedure.type === "variable";
const isJSONataContains = (expr) => isJSONataExprNode(expr) && expr.type === "function" && expr.value === "(" && Array.isArray(expr.arguments) && expr.arguments.length >= 2 && isJSONataExprNode(expr.arguments[0]) && isJSONataExprNode(expr.procedure) && expr.procedure.value === "contains" && expr.procedure.type === "variable";
const isJSONataToMillis = (expr) => isJSONataExprNode(expr) && expr.type === "function" && expr.value === "(" && Array.isArray(expr.arguments) && expr.arguments.length > 0 && isJSONataString(expr.arguments[0]) && isJSONataExprNode(expr.procedure) && expr.procedure.value === "toMillis" && expr.procedure.type === "variable";
const isJSONataList = (expr) => isJSONataExprNode(expr) && expr.type === "unary" && expr.value === "[" && Array.isArray(expr.expressions);
const isJSONataPrimitive = (expr) => {
	return isJSONataString(expr) || isJSONataNumber(expr) || isJSONataBoolean(expr) || isJSONataNull(expr) || isJSONataToMillis(expr);
};
const isJSONataPrimitiveList = (expr) => isJSONataList(expr) && expr.expressions.every((v) => isJSONataPrimitive(v));
const isJSONataIdentifierList = (expr) => isJSONataList(expr) && expr.expressions.every((v) => isJSONataIdentifier(v));
const isJSONataValidValue = (expr) => isJSONataPrimitive(expr) || isJSONataRegex(expr) || isJSONataIdentifier(expr) || isJSONataPrimitiveList(expr) || isJSONataIdentifierList(expr) || isJSONataToMillis(expr);
const isJSONataComparison = (expr) => isJSONataEqual(expr) || isJSONataNotEqual(expr) || isJSONataGreaterThan(expr) || isJSONataGreaterThanOrEqual(expr) || isJSONataLessThan(expr) || isJSONataLessThanOrEqual(expr);
const getValidValue = (expr) => {
	if (isJSONataToMillis(expr)) return getValidValue(expr.arguments[0]);
	else if (isJSONataIdentifier(expr)) return getFieldFromPath(expr);
	else if (isJSONataPrimitiveList(expr)) return expr.expressions.map((v) => getValidValue(v));
	else if (isJSONataIdentifierList(expr)) return expr.expressions.map((v) => getFieldFromPath(v));
	return expr.value;
};
const getFieldFromPath = (path) => isJSONataIdentifier(path) ? path.steps.map((s) => s.value).join(".") : "";
const normalizeOperator = (opType, flip) => {
	if (flip) {
		if (opType === "<") return ">";
		if (opType === "<=") return ">=";
		if (opType === ">") return "<";
		if (opType === ">=") return "<=";
	}
	return opType;
};
const negatedLikeOperators = {
	contains: "doesNotContain",
	beginsWith: "doesNotBeginWith",
	endsWith: "doesNotEndWith"
};
const generateFlatAndOrList = (expr) => {
	// istanbul ignore else
	if (isJSONataAnd(expr) || isJSONataOr(expr)) {
		const { lhs, rhs, value: combinator } = expr;
		if (isJSONataAnd(lhs) || isJSONataOr(lhs)) return [
			...generateFlatAndOrList(lhs),
			combinator,
			rhs
		];
		return [
			lhs,
			combinator,
			rhs
		];
	}
	// istanbul ignore next
	return [];
};
const generateMixedAndOrList = (expr) => {
	const arr = generateFlatAndOrList(expr);
	const returnArray = [];
	let startIndex = 0;
	for (let i = 0; i < arr.length; i += 2) if (arr[i + 1] === "and") {
		startIndex = i;
		let j = 1;
		while (arr[startIndex + j] === "and") {
			i += 2;
			j += 2;
		}
		const tempAndArray = arr.slice(startIndex, i + 1);
		returnArray.push(tempAndArray);
		i -= 2;
	} else if (arr[i + 1] === "or") if (i === 0 || i === arr.length - 3) {
		if (i === 0 || arr[i - 1] === "or") returnArray.push(arr[i]);
		returnArray.push(arr[i + 1]);
		if (i === arr.length - 3) returnArray.push(arr[i + 2]);
	} else if (arr[i - 1] === "and") returnArray.push(arr[i + 1]);
	else returnArray.push(arr[i], arr[i + 1]);
	if (returnArray.length === 1 && Array.isArray(returnArray[0])) return returnArray[0];
	return returnArray;
};

//#endregion
//#region src/utils/parseJSONata/parseJSONata.ts
function parseJSONata(jsonataInput, options = {}) {
	const { fields, independentCombinators, listsAsArrays: _laa } = options;
	const ic = !!independentCombinators;
	const fieldsFlat = getFieldsArray(fields);
	const fieldIsValid = (fieldName, operator, subordinateFieldName) => fieldIsValidUtil({
		fieldName,
		fieldsFlat,
		operator,
		subordinateFieldName,
		getValueSources: options?.getValueSources
	});
	const emptyQuery = {
		rules: [],
		...ic ? {} : { combinator: "and" }
	};
	const parseJSONataAST = (expr, processOpts = {}) => {
		const { forwardNegation: _forwardedNegation, groupOnlyIfNecessary: _g } = processOpts;
		if (isJSONataBlock(expr)) {
			if (isJSONataAnd(expr.expressions[0]) || isJSONataOr(expr.expressions[0]) || isJSONataBlock(expr.expressions[0])) return parseJSONataAST(expr.expressions[0]);
			const blockOfExpr = parseJSONataAST(expr.expressions[0]);
			// istanbul ignore else
			if (blockOfExpr) return ic ? { rules: [blockOfExpr] } : {
				combinator: "and",
				rules: [blockOfExpr]
			};
		} else if (isJSONataAnd(expr) || isJSONataOr(expr)) {
			if (ic) {
				const rules$1 = generateFlatAndOrList(expr).map((v) => {
					if (typeof v === "string") return v;
					return parseJSONataAST(v);
				});
				if (!rules$1.every(Boolean)) return null;
				if (((rs) => rs.length === 3 && (rs[1] === "and" || rs[1] === "or") && !isRuleGroup(rs[0]) && !isRuleGroup(rs[2]))(rules$1) && rules$1[0].field === rules$1[2].field && (rules$1[0].valueSource ?? "value") === (rules$1[2].valueSource ?? "value") && (rules$1[1] === "and" && (rules$1[0].operator === ">=" && rules$1[2].operator === "<=" || rules$1[0].operator === "<=" && rules$1[2].operator === ">=") || rules$1[1] === "or" && (rules$1[0].operator === ">" && rules$1[2].operator === "<" || rules$1[0].operator === "<" && rules$1[2].operator === ">"))) return {
					field: rules$1[0].field,
					operator: rules$1[1] === "and" ? "between" : "notBetween",
					value: rules$1[1] === "and" && rules$1[0].operator === "<=" || rules$1[1] === "or" && rules$1[0].operator === ">" ? [rules$1[2].value, rules$1[0].value] : [rules$1[0].value, rules$1[2].value],
					...rules$1[0].valueSource ? { valueSource: rules$1[0].valueSource } : null
				};
				return { rules: rules$1 };
			}
			const andOrList = generateMixedAndOrList(expr);
			const combinator = andOrList[1];
			const rules = andOrList.filter((v) => Array.isArray(v) || !!v && typeof v !== "string" && "type" in v).map((v) => Array.isArray(v) ? v.filter((vf) => !!v && typeof vf !== "string" && "type" in vf) : v).map((exp) => {
				if (Array.isArray(exp)) return {
					combinator: "and",
					rules: exp.map((e) => parseJSONataAST(e)).filter(Boolean)
				};
				return parseJSONataAST(exp);
			}).filter(Boolean);
			if (((rs) => rs.length === 2 && !isRuleGroup(rs[0]) && !isRuleGroup(rs[1]))(rules) && rules[0].field === rules[1].field && (rules[0].valueSource ?? "value") === (rules[1].valueSource ?? "value") && (combinator === "and" && (rules[0].operator === ">=" && rules[1].operator === "<=" || rules[0].operator === "<=" && rules[1].operator === ">=") || combinator === "or" && (rules[0].operator === ">" && rules[1].operator === "<" || rules[0].operator === "<" && rules[1].operator === ">"))) return {
				field: rules[0].field,
				operator: combinator === "and" ? "between" : "notBetween",
				value: combinator === "and" && rules[0].operator === "<=" || combinator === "or" && rules[0].operator === ">" ? [rules[1].value, rules[0].value] : [rules[0].value, rules[1].value],
				...rules[0].valueSource ? { valueSource: rules[0].valueSource } : null
			};
			// istanbul ignore else
			if (rules.length > 0) return {
				combinator,
				rules
			};
		} else if (isJSONataNot(expr)) {
			const negatedExpr = parseJSONataAST(expr.arguments[0]);
			// istanbul ignore else
			if (negatedExpr) {
				if (!isRuleGroup(negatedExpr) && (negatedExpr.operator === "contains" || negatedExpr.operator === "beginsWith" || negatedExpr.operator === "endsWith")) return {
					...negatedExpr,
					operator: negatedLikeOperators[negatedExpr.operator]
				};
				return ic ? {
					rules: [negatedExpr],
					not: true
				} : {
					combinator: "and",
					rules: [negatedExpr],
					not: true
				};
			}
		} else if (isJSONataContains(expr)) {
			const [arg1, arg2] = expr.arguments;
			let field = "";
			let regex = "";
			let valueSource = void 0;
			// istanbul ignore else
			if (isJSONataIdentifier(arg1)) {
				field = getFieldFromPath(arg1);
				if (isJSONataIdentifier(arg2)) {
					regex = getFieldFromPath(arg2);
					valueSource = "field";
				} else if (isJSONataString(arg2) || isJSONataRegex(arg2)) regex = getValidValue(arg2);
			}
			// istanbul ignore else
			if (valueSource === "field" ? fieldIsValid(field, "contains", regex) : fieldIsValid(field, "contains")) return {
				field,
				operator: "contains",
				value: regex,
				...valueSource ? { valueSource } : {}
			};
		} else if (isJSONataIn(expr)) {
			const field = getFieldFromPath(expr.lhs);
			let valueSource = void 0;
			if (isJSONataIdentifierList(expr.rhs)) valueSource = "field";
			if (isJSONataValidValue(expr.rhs)) {
				const value = getValidValue(expr.rhs);
				// istanbul ignore else
				if (field && value.every((v) => fieldIsValid(field, "in", valueSource === "field" ? v : void 0))) return {
					field,
					operator: "in",
					value,
					...valueSource ? { valueSource } : {}
				};
			}
		} else if (isJSONataComparison(expr)) {
			let field = null;
			let value = void 0;
			let valueSource = void 0;
			let flip = false;
			const { lhs, rhs } = expr;
			if (isJSONataIdentifier(lhs) && isJSONataValidValue(rhs)) {
				field = getFieldFromPath(lhs);
				value = getValidValue(rhs);
				if (isJSONataIdentifier(rhs)) valueSource = "field";
			} else if (isJSONataIdentifier(rhs) && isJSONataValidValue(lhs)) {
				flip = true;
				field = getFieldFromPath(rhs);
				value = getValidValue(lhs);
			}
			let operator = normalizeOperator(expr.value, flip);
			if (value === null && (operator === "=" || operator === "!=")) operator = operator === "=" ? "null" : "notNull";
			if (field && fieldIsValid(field, operator, valueSource === "field" ? value : void 0) && value !== void 0) return valueSource ? {
				field,
				operator,
				value,
				valueSource
			} : {
				field,
				operator,
				value
			};
		}
		return null;
	};
	const prepare = options.generateIDs ? prepareRuleGroup : (g) => g;
	let jsonataExpr;
	try {
		jsonataExpr = jsonata(jsonataInput);
	} catch {
		return prepare(emptyQuery);
	}
	const result = parseJSONataAST(jsonataExpr.ast());
	if (result) {
		if (isRuleGroup(result)) return prepare(result);
		return prepare({
			rules: [result],
			...ic ? {} : { combinator: "and" }
		});
	}
	return prepare(emptyQuery);
}

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