import { CardinalityTypeEnums, NodeGroupOutlierEnums, NodeGroupTypeEnums } from "../../enums/unitySystemEnums.mjs";
import { toLowerFirstChar, toUpperFirstChar } from "../input/StringUtilities.mjs";
import { evaluateRule, mapRule } from "../rules/RuleUtilities.mjs";
import { getSearchIdentifiers, getSearchObject } from "../search/SearchUtilities.mjs";
import GroupNode from "../../models/GroupNode.mjs";
import * as Icons from "@fluentui/react-icons";
import { cloneDeep, orderBy } from "lodash-es";
import { v4 } from "uuid";
//#region src/utilities/tree/TreeUtilities.js
const makeTreeStructure = (treeData, key, parentKey, parentGroupKey = "parentGroupId") => {
	if (!treeData) return [];
	const keys = [];
	treeData.forEach((node) => {
		node.children = [];
		if (node["isExpanded"] === void 0 && !node.isGroupNode) if (node.properties.defaultDisplay === "collapsed" || node.properties.lazyLoad) node.isExpanded = false;
		else node.isExpanded = true;
		keys.push(node[key]);
	});
	const roots = treeData.filter((node) => {
		return !(node?.isGroupNode ? node[parentGroupKey] : node[parentKey]);
	});
	const nodes = [];
	const existingGroups = [];
	roots.forEach((root) => {
		nodes.push(root);
	});
	while (nodes.length > 0) {
		const node = nodes.pop();
		treeData.filter((data) => data[parentKey] === node[key] || data[parentGroupKey] === node[key]).forEach((child) => {
			if (child?.isGroupNode) {
				if (!existingGroups.find((eg) => eg.id === child.id && eg.parentGroupId === child.parentGroupId)) {
					existingGroups.push(child);
					node.children.push(child);
					nodes.push(child);
				}
			} else if (node.isGroupNode && child.parentGroupId || !node.isGroupNode && !child.parentGroupId) {
				node.children.push(child);
				nodes.push(child);
			}
		});
	}
	const removeEmptyGroupNodes = (node) => {
		if (node?.isGroupNode && node?.hideEmptyGroups && !node?.children?.length) return null;
		node.children = node.children.map(removeEmptyGroupNodes).filter((child) => child !== null);
		return node;
	};
	const filteredRoots = roots.map(removeEmptyGroupNodes).filter((root) => root !== null);
	if (filteredRoots.length === 1) return filteredRoots[0];
	return filteredRoots;
};
const makeTreeStaticGroupStructure = (treeData, key, parentKey, groupType = NodeGroupTypeEnums.Static, hideEmptyGroups) => {
	if (!treeData) return [];
	const keys = [];
	treeData.forEach((node, index) => {
		const { id, hideEmptyGroups, children, apiMethodInstanceId, parentGroupId, order, isExpanded, ...groupProperties } = node;
		treeData[index] = new GroupNode({
			id,
			groupType,
			children,
			parentId: parentGroupId,
			parentGroupId,
			isExpanded,
			properties: { ...groupProperties }
		});
		keys.push(node[key]);
	});
	const roots = treeData.filter((node) => keys.indexOf(node[parentKey]) === -1);
	const nodes = [];
	roots.forEach((root) => {
		nodes.push(root);
	});
	while (nodes.length > 0) {
		const node = nodes.pop();
		treeData.filter((data) => data[parentKey] === node[key]).forEach((child) => {
			node.children.push(child);
			nodes.push(child);
		});
	}
	if (roots.length === 1) return roots[0];
	return roots;
};
const makeDynamicGroupStructures = (treeStructure, results) => {
	if (!treeStructure) return [];
	const groupStructures = [];
	results.forEach((item) => {
		processDynamicGroupForCurrentNodeLevel(item, treeStructure, groupStructures, groupStructures);
	});
	return groupStructures;
};
const processDynamicGroupForCurrentNodeLevel = (item, node, groupStructures, previousFilteredGroups = []) => {
	const { property, id } = node;
	const label = property ? getLabelFromProperty(item, property) : null;
	let filteredGroups = [];
	previousFilteredGroups.forEach((group) => {
		if (group) {
			const foundGroups = findNodesByIdAndLabel(group, id, label);
			if (foundGroups.length) filteredGroups = filteredGroups.concat(foundGroups);
		}
	});
	if (filteredGroups.length) {
		if (node?.children?.length) node.children.forEach((child) => processDynamicGroupForCurrentNodeLevel(item, child, groupStructures, filteredGroups));
	} else if (label) {
		const dynamicGroupTree = makeDynamicGroupTree(node, item);
		if (node.parentGroupId) previousFilteredGroups.forEach((filteredGroup) => {
			const matchingGroupNode = findNodeById(filteredGroup, node.parentGroupId);
			if (matchingGroupNode) {
				dynamicGroupTree.parentGroupId = matchingGroupNode.id;
				matchingGroupNode.children.push(dynamicGroupTree);
			}
		});
		else groupStructures.push(dynamicGroupTree);
	}
};
const makeDynamicGroupTree = (node, item, parentGroupNode) => {
	const { id, children, apiMethodInstanceId, parentGroupId, order, property, label, isExpanded, ...groupProperties } = node;
	const updatedLabel = property ? getLabelFromProperty(item, property) : null;
	if (updatedLabel) {
		const groupNode = new GroupNode({
			id: `${id}`,
			groupType: NodeGroupTypeEnums.Dynamic,
			children: [],
			parentGroupId: parentGroupNode?.id || null,
			isExpanded,
			properties: {
				label: updatedLabel,
				...groupProperties,
				propertyKey: property
			}
		});
		if (parentGroupNode) parentGroupNode.children.push(groupNode);
		if (children?.length) children.forEach((child) => makeDynamicGroupTree(child, item, groupNode));
		return groupNode;
	}
};
const makeDynamicTreeStructure = (treeData, key, parentKey) => {
	if (!treeData) return [];
	const keys = [];
	treeData.forEach((node, index) => {
		keys.push(node[key]);
	});
	const roots = treeData.filter((node) => keys.indexOf(node[parentKey]) === -1);
	const nodes = [];
	roots.forEach((root) => {
		nodes.push(root);
	});
	while (nodes.length > 0) {
		const node = nodes.pop();
		treeData.filter((data) => data[parentKey] === node[key]).forEach((child) => {
			node.children.push(child);
			nodes.push(child);
		});
	}
	if (roots.length === 1) return roots[0];
	return roots;
};
const getIconFromName = (name) => {
	if (!name) return null;
	if (name.slice(-4).toLowerCase() !== "icon") return Icons[`${name}Icon`] || null;
	else return Icons[name] || null;
};
const findLastNode = (tree) => {
	let result = null;
	if (!tree?.children?.length) return tree;
	else {
		if (tree?.children) tree.children.forEach((node) => result = findLastNode(node));
		return result;
	}
};
const searchTree = (tree, id) => {
	let result = null;
	if (tree.id === id) return tree;
	else {
		if (tree.children) tree.children.some((node) => result = searchTree(node, id));
		return result;
	}
};
const deleteNode = (treeData, nodeId) => {
	const updatedTreeData = [...treeData];
	const foundNode = updatedTreeData.find((node) => node.id === nodeId);
	const nodeIndex = updatedTreeData.findIndex((node) => node.id === nodeId);
	if (!foundNode.parentId || !updatedTreeData.some((node) => node.parentId === nodeId)) {
		if (nodeIndex > -1) updatedTreeData.splice(nodeIndex, 1);
		const immediateChild = updatedTreeData.find((node) => node.parentId === nodeId);
		if (immediateChild) immediateChild.parentId = null;
	} else {
		foundNode.isDeleted = true;
		foundNode.properties = {};
	}
	return updatedTreeData;
};
const deleteNodeAndChildren = (treeData, nodeId) => {
	const updatedTreeData = [...treeData];
	const nodeIdsToDelete = [];
	nodeIdsToDelete.push(nodeId);
	getAllChildrenNodesToDelete(updatedTreeData, nodeId, nodeIdsToDelete);
	return updatedTreeData.filter((node) => !nodeIdsToDelete.includes(node.id));
};
const getAllChildrenNodesToDelete = (treeData, nodeId, nodeIdsToDelete) => {
	treeData.filter((node) => node.parentId === nodeId).forEach((node) => {
		nodeIdsToDelete.push(node.id);
		getAllChildrenNodesToDelete(treeData, node.id, nodeIdsToDelete);
	});
};
const processCatalogObjectKeysInOrder = (tree, keys) => {
	if (!tree?.children?.length) keys.push(tree?.properties?.catalogObjectKey);
	else if (tree?.children) {
		if (tree?.properties?.catalogObjectKey) keys.push(tree?.properties?.catalogObjectKey);
		tree.children.forEach((node) => processCatalogObjectKeysInOrder(node, keys));
	}
};
const processOrderedTreeData = (tree, treeData) => {
	if (!tree?.children?.length) treeData.push(tree);
	else if (tree?.children) {
		treeData.push(tree);
		tree.children.forEach((node) => processOrderedTreeData(node, treeData));
	}
};
const processObjectToTree = (result, treeData, objectReferenceKeys, treeList, catalogObjects, promotedEntities, wasLazyLoaded) => {
	processReferences(result, objectReferenceKeys, { ...treeData }, 0, treeList, null, catalogObjects, promotedEntities, wasLazyLoaded);
};
const processReferences = (reference, objectReferenceKeys, treeData, index, treeList, parentId, catalogObjects, promotedEntities, wasLazyLoaded) => {
	const newIndex = index + 1;
	if (reference) {
		let node = parentId ? treeData[newIndex] : treeData[0];
		let nodeGroups = [];
		if (parentId) {
			if (node?.properties?.groupConfiguration?.groupType === NodeGroupTypeEnums.Static) nodeGroups = constructStaticNodeGroups(node, true);
			else if (node?.properties?.groupConfiguration?.groupType === NodeGroupTypeEnums.Dynamic) nodeGroups = constructDynamicNodeGroups(reference, node, true);
		}
		if (Array.isArray(reference) && reference.length) reference.forEach((ref, i) => {
			if (node) {
				const nodeCopy = cloneDeep(node);
				processObjIndex(nodeCopy, ref, i, parentId, catalogObjects, promotedEntities, wasLazyLoaded);
				if (nodeGroups.length) {
					if (node?.properties?.groupConfiguration?.groupType === NodeGroupTypeEnums.Static) {
						const groupedItemIndexes = /* @__PURE__ */ new Set();
						let processedItem = {
							itemAdded: false,
							nodeChildren: []
						};
						nodeGroups.forEach((nodeGroup) => {
							let nodeGroupChildren = [];
							processedItem = processItemForStaticNodeGroup(nodeGroup, ref, groupedItemIndexes, nodeCopy, i, /* @__PURE__ */ new Set(), treeList);
							nodeGroupChildren = nodeGroupChildren.concat(processedItem.nodeChildren);
							mapNodeGroupChildren(nodeGroup, nodeGroupChildren);
							nodeGroup.parentGroupId = nodeCopy.parentId;
						});
						if (!processedItem.itemAdded && node?.properties?.groupConfiguration?.outlier === NodeGroupOutlierEnums.Individual) !checkNodeIsHidden(nodeCopy, ref, wasLazyLoaded) && treeList.push(nodeCopy);
					} else if (node?.properties?.groupConfiguration?.groupType === NodeGroupTypeEnums.Dynamic) nodeGroups.forEach((nodeGroup) => {
						nodeGroup.parentGroupId = nodeCopy.parentId;
						nodeGroup.parentId = nodeCopy.parentId;
						processGroupNodesAndAddToTreeList(nodeGroup, treeList, nodeCopy.parentId, ref, wasLazyLoaded);
					});
				} else !checkNodeIsHidden(nodeCopy, ref, wasLazyLoaded) && treeList.push(nodeCopy);
				if (nodeCopy?.children?.length) {
					const objectReferenceKeysCopy = [...objectReferenceKeys];
					nodeCopy.children.forEach((childNode, i) => {
						const catalogObjectKey = childNode?.properties?.catalogObjectKey;
						const nextIndex = objectReferenceKeysCopy.indexOf(catalogObjectKey);
						if (!parentId) objectReferenceKeysCopy[nextIndex] = null;
						processReferences(ref[catalogObjectKey], objectReferenceKeys, treeData, nextIndex, treeList, nodeCopy.id, catalogObjects, promotedEntities, nodeCopy.properties.lazyLoad);
					});
				}
			}
		});
		else if (typeof reference === "object" && !Array.isArray(reference)) {
			processObjIndex(node, reference, 0, parentId, catalogObjects, promotedEntities, wasLazyLoaded);
			if (node) {
				const nodeCopy = cloneDeep(node);
				!checkNodeIsHidden(nodeCopy, reference, wasLazyLoaded) && treeList.push(nodeCopy);
				if (nodeCopy?.children?.length) {
					const objectReferenceKeysCopy = [...objectReferenceKeys];
					nodeCopy.children.forEach((childNode, i) => {
						const catalogObjectKey = childNode?.properties?.catalogObjectKey;
						const nextIndex = parentId ? newIndex : objectReferenceKeysCopy.indexOf(catalogObjectKey);
						if (!parentId) objectReferenceKeysCopy[nextIndex] = null;
						processReferences(reference[catalogObjectKey], objectReferenceKeys, treeData, nextIndex, treeList, nodeCopy.id, catalogObjects, promotedEntities, nodeCopy.properties.lazyLoad);
					});
				}
			}
		}
	}
};
const processObjIndex = (node, obj, index, parentId, catalogObjects, promotedEntities, wasLazyLoaded) => {
	if (node.properties.conditionalNodeIconExpression) {
		const conditionalNodeIcon = evaluateRule(node.properties.conditionalNodeIconExpression, obj, node.properties?.joiningEntityCatalogObjectKey, wasLazyLoaded);
		if (conditionalNodeIcon) {
			node.properties["conditionalNodeIconName"] = conditionalNodeIcon?.name || "";
			node.properties["conditionalNodeIconColor"] = conditionalNodeIcon?.iconColor?.hex;
			node.properties["conditionalNodeIconType"] = conditionalNodeIcon?.type || "";
		} else {
			node.properties["conditionalNodeIconName"] = "";
			node.properties["conditionalNodeIconColor"] = "";
			node.properties["conditionalNodeIconType"] = "";
		}
	}
	if (node.properties.conditionalNodeAdornmentExpression || node.properties.conditionalIconExpression) {
		const conditionalNodeAdornment = node.properties.conditionalNodeAdornmentExpression ? evaluateRule(node.properties.conditionalNodeAdornmentExpression, obj, node.properties?.joiningEntityCatalogObjectKey, wasLazyLoaded) : evaluateRule(node.properties.conditionalIconExpression, obj, node.properties?.joiningEntityCatalogObjectKey, wasLazyLoaded);
		if (conditionalNodeAdornment) {
			node.properties["conditionalNodeAdornmentName"] = conditionalNodeAdornment?.name || "";
			node.properties["conditionalNodeAdornmentColor"] = conditionalNodeAdornment?.iconColor?.hex;
			node.properties["conditionalNodeAdornmentType"] = conditionalNodeAdornment?.type || "";
		} else {
			node.properties["conditionalNodeAdornmentName"] = "";
			node.properties["conditionalNodeAdornmentColor"] = "";
			node.properties["conditionalNodeAdornmentType"] = "";
		}
	}
	if (node.properties.catalogReturnObject) {
		let searchIdentifiers = getSearchIdentifiers(catalogObjects, node.properties.catalogReturnObject);
		node.properties["searchIdentifier"] = searchIdentifiers?.join(",");
		const associatedTreePrimaryKeyMap = node.properties.associatedTreePrimaryKeyMap;
		if (!!associatedTreePrimaryKeyMap) {
			searchIdentifiers = Object.keys(associatedTreePrimaryKeyMap);
			node.properties["searchIdentifier"] = searchIdentifiers;
		}
		node.properties["filterElements"] = [];
		const searchValues = [];
		const joiningEntityCatalogObjectKey = node?.properties?.joiningEntityCatalogObjectKey;
		searchIdentifiers.forEach((searchIdentifier) => {
			const searchField = searchIdentifier ? searchIdentifier.charAt(0).toUpperCase() + searchIdentifier.slice(1) : "";
			let searchValue = "";
			let si = associatedTreePrimaryKeyMap?.[searchIdentifier] ? associatedTreePrimaryKeyMap?.[searchIdentifier] : searchIdentifier;
			if (obj[si]) searchValue = obj[si];
			else if (joiningEntityCatalogObjectKey) searchValue = obj[joiningEntityCatalogObjectKey] ? obj[joiningEntityCatalogObjectKey][si] : "";
			node.properties["filterElements"].push({
				searchField,
				searchOperator: "=",
				searchValue: searchValue ?? ""
			});
			searchValues.push(searchValue);
		});
		node.properties["searchValue"] = searchValues.toString();
	}
	node.properties["nodeLabel"] = getDisplayName(node, obj);
	node.properties["nodeSubLabel"] = getDisplayDetails(node, obj);
	node.properties["headerTitle"] = getHeaderTitle(node, obj);
	node.parentId = parentId;
	node["entityNodeParentId"] = parentId;
	node.id = v4();
	node.nodeObj = obj;
	if (node?.properties?.lazyLoad) node.lazyLoadChildrenArr = getLazyLoadChildrenArr(node, catalogObjects, promotedEntities);
};
const getEntityAssoc = (nodeEntity, node) => {
	let entityAssoc = null;
	if (nodeEntity) {
		const referenceProperty = nodeEntity.properties.find((property) => {
			if (node.properties?.joiningEntityName) return property.reference === node.properties?.joiningEntityName;
			else return property.reference === node.properties?.catalogReturnObject;
		});
		entityAssoc = referenceProperty ? referenceProperty.extendedProperties?.childEntityAssoc : null;
	}
	return entityAssoc;
};
const getLazyLoadChildrenArr = (node, catalogObjects, promotedEntities) => {
	const lazyLoadChildrenArr = [];
	let defaultSearchIdentifiers = [];
	if (node?.properties?.catalogReturnObject) defaultSearchIdentifiers = getSearchIdentifiers(catalogObjects, node.properties.catalogReturnObject);
	if (!node || !node.children) return lazyLoadChildrenArr;
	const pageSize = parseInt(node.properties?.noOfNodesDisplayed) || 50;
	node.children.forEach((childNode) => {
		const lazyNodeSearchObj = {
			apiMethodId: null,
			data: null,
			parentNodeRefKey: childNode.properties?.catalogObjectKey,
			catalogReturnObject: childNode.properties?.catalogReturnObject
		};
		const entityName = childNode.properties?.catalogReturnObject;
		const promotedEntity = promotedEntities?.find((pe) => pe.entityName === entityName);
		let searchIdentifiers = [];
		const filterElements = [];
		if (promotedEntity) {
			let baseSearch = promotedEntity.unityBaseSearchMethod;
			let childBaseSearch = promotedEntity.unityBaseSearchMethod;
			const nodeEntity = catalogObjects?.find((co) => co.catalogObjectName === node.properties?.catalogReturnObject);
			let isManyToManySearch = false;
			let usingJoiningTableForSearch = false;
			if (nodeEntity) {
				const childEntityAssoc = getEntityAssoc(nodeEntity, childNode);
				let joiningEntityName = null;
				let promotedEntityForJoiningTable = null;
				if (childEntityAssoc.Cardinality === CardinalityTypeEnums.Many_To_Many) {
					isManyToManySearch = true;
					lazyNodeSearchObj["manyToManyKeys"] = [];
					joiningEntityName = childNode.properties?.joiningEntityName;
					promotedEntityForJoiningTable = promotedEntities?.find((pe) => pe.entityName === joiningEntityName);
					if (promotedEntityForJoiningTable?.unityBaseSearchMethod) {
						baseSearch = promotedEntityForJoiningTable.unityBaseSearchMethod;
						lazyNodeSearchObj.manyToManyJointEntityApiMethodId = childBaseSearch?.apiMethodId;
						usingJoiningTableForSearch = true;
					}
					const entityAssoc = getEntityAssoc(catalogObjects.find((co) => co.catalogObjectName === childNode.properties?.catalogReturnObject), childNode);
					if (entityAssoc && Object.keys(entityAssoc).length) entityAssoc.Keys.forEach((keyVal) => {
						const keyValArr = keyVal.split(",");
						const foreignKeyName = keyValArr[0] ? keyValArr[0].trim() : "";
						const parentIdentifierName = keyValArr[1] ? keyValArr[1].trim() : "";
						const searchValueKey = /^[A-Z]*$/.test(parentIdentifierName) ? parentIdentifierName.toLowerCase() : toLowerFirstChar(parentIdentifierName);
						lazyNodeSearchObj["manyToManyKeys"].push({
							searchItemIdentifier: usingJoiningTableForSearch ? /^[A-Z]*$/.test(foreignKeyName) ? foreignKeyName.toLowerCase() : toLowerFirstChar(foreignKeyName) : searchValueKey,
							searchNameKey: foreignKeyName,
							searchValueKey
						});
					});
				}
				if (childEntityAssoc && Object.keys(childEntityAssoc).length) childEntityAssoc.Keys.forEach((keyVal) => {
					const keyValArr = keyVal.split(",");
					let searchJoiningEntity = "";
					if (!isManyToManySearch && node.nodeObj.hasOwnProperty(node.properties.joiningEntityCatalogObjectKey)) searchJoiningEntity = node.properties.joiningEntityCatalogObjectKey;
					const foreignKeyName = keyValArr[0] ? keyValArr[0].trim() : "";
					let siObj = {
						searchNameKey: keyValArr[1] ? keyValArr[1].trim() : "",
						searchValueKey: /^[A-Z]*$/.test(foreignKeyName) ? foreignKeyName.toLowerCase() : toLowerFirstChar(foreignKeyName),
						searchJoiningEntity
					};
					if (isManyToManySearch && !usingJoiningTableForSearch) siObj = {
						searchNameKey: foreignKeyName,
						searchValueKey: /^[A-Z]*$/.test(foreignKeyName) ? foreignKeyName.toLowerCase() : toLowerFirstChar(foreignKeyName)
					};
					if (isManyToManySearch) {
						if (childNode.properties?.catalogObjectKey && childNode.properties?.joiningEntityCatalogObjectLeftKey) {
							siObj["joiningEntityKeyName"] = toUpperFirstChar(!usingJoiningTableForSearch ? childNode.properties?.joiningEntityChildKey : childNode.properties?.catalogObjectKey);
							siObj["joiningEntityCatalogObjectLeftKeyName"] = toUpperFirstChar(childNode.properties?.joiningEntityCatalogObjectLeftKey);
						}
						if (promotedEntityForJoiningTable?.unityBaseSearchMethod) {
							siObj["joiningEntityKeyName"] = null;
							siObj["joiningEntityCatalogObjectLeftKeyName"] = null;
						}
					}
					searchIdentifiers.push(siObj);
				});
			}
			if (!searchIdentifiers.length) defaultSearchIdentifiers.forEach((searchIdentifier) => {
				const siObj = {
					searchNameKey: searchIdentifier,
					searchValueKey: searchIdentifier
				};
				if (childNode.properties?.catalogObjectKey && childNode.properties?.joiningEntityCatalogObjectLeftKey) {
					siObj["joiningEntityKeyName"] = toUpperFirstChar(childNode.properties?.catalogObjectKey);
					siObj["joiningEntityCatalogObjectLeftKeyName"] = toUpperFirstChar(childNode.properties?.joiningEntityCatalogObjectLeftKey);
				}
				searchIdentifiers.push(siObj);
			});
			searchIdentifiers.forEach((si) => {
				let searchValue = "";
				if (si?.searchJoiningEntity) searchValue = node.nodeObj[si.searchJoiningEntity][si.searchValueKey];
				else if (usingJoiningTableForSearch) {
					const joiningEntityCatalogObjectKey = node?.properties?.joiningEntityCatalogObjectKey;
					const value = node?.nodeObj?.[joiningEntityCatalogObjectKey];
					searchValue = value ? value[si.searchValueKey] : node.nodeObj[si.searchValueKey];
				} else searchValue = node.nodeObj[si.searchValueKey];
				let formattedPropertyName = toUpperFirstChar(si.searchNameKey);
				if (si["joiningEntityKeyName"] && si["joiningEntityCatalogObjectLeftKeyName"]) formattedPropertyName = `${si["joiningEntityKeyName"]}.${si["joiningEntityCatalogObjectLeftKeyName"]}.${formattedPropertyName}`;
				filterElements.push({
					searchField: formattedPropertyName,
					searchValue,
					searchOperator: "="
				});
			});
			lazyNodeSearchObj.data = getSearchObject(filterElements, 1, pageSize);
			lazyNodeSearchObj.pageSize = pageSize;
			lazyNodeSearchObj.apiMethodId = baseSearch?.apiMethodId || null;
			lazyLoadChildrenArr.push(lazyNodeSearchObj);
		} else {
			console.log("Error: Promote " + entityName + " entity");
			node.errorRetrievingChildren = "Error: Promote " + entityName + " child entity";
		}
	});
	return lazyLoadChildrenArr;
};
const getVaryingChildKey = (searchMethod, catalogObjects) => {
	const childPkFields = getSearchIdentifiers(catalogObjects, searchMethod?.catalogReturnObject);
	if (!childPkFields?.length) return null;
	const fixedFieldNames = new Set((searchMethod?.data?.filterElements || []).map((fe) => fe.searchField).filter(Boolean).map((n) => n.toLowerCase()));
	return childPkFields.find((pk) => !fixedFieldNames.has(pk.toLowerCase())) || null;
};
const collectChildVaryingKeysByType = (parentNode, catalogObjects, childrenOverride = null) => {
	const children = childrenOverride || parentNode?.children || [];
	const result = {};
	for (const child of children) {
		if (child?.isGroupNode) continue;
		const type = child?.properties?.catalogReturnObject;
		if (!type) continue;
		const sm = parentNode?.lazyLoadChildrenArr?.find((m) => m.catalogReturnObject === type);
		if (!sm) continue;
		const varyingField = getVaryingChildKey(sm, catalogObjects);
		if (!varyingField) continue;
		const value = child.nodeObj?.[varyingField];
		if (value == null) continue;
		if (!result[type]) result[type] = [];
		result[type].push(value);
	}
	return result;
};
const keysByTypeToFilterArray = (keysByType) => Object.entries(keysByType || {}).map(([entityType, keys]) => ({
	entityType,
	keys
}));
const fetchCountsByType = async (parentNode, executeQueryAdHoc) => {
	const out = {};
	if (!parentNode?.lazyLoadChildrenArr?.length) return out;
	const responses = await Promise.all(parentNode.lazyLoadChildrenArr.map((sm) => executeQueryAdHoc({ data: {
		...sm.data,
		pageNumber: 1,
		pageSize: 1
	} }, sm.apiMethodId).catch(() => null)));
	parentNode.lazyLoadChildrenArr.forEach((sm, i) => {
		const total = responses[i]?.data?.total;
		if (typeof total === "number") out[sm.catalogReturnObject] = total;
	});
	return out;
};
const getFilters = (searchMethod, catalogObjects, { includeKeys = null, excludeKeys = null } = {}) => {
	const base = searchMethod?.data?.filterElements || [];
	const hasInclude = Array.isArray(includeKeys) && includeKeys.length > 0;
	const hasExclude = Array.isArray(excludeKeys) && excludeKeys.length > 0;
	if (!hasInclude && !hasExclude) return base;
	const varyingField = getVaryingChildKey(searchMethod, catalogObjects);
	if (!varyingField) return base;
	const fieldName = toUpperFirstChar(varyingField);
	const out = [...base];
	if (hasInclude) out.push({
		searchField: fieldName,
		searchValue: includeKeys.join(","),
		searchOperator: "IN"
	});
	if (hasExclude) out.push({
		searchField: fieldName,
		searchValue: excludeKeys.join(","),
		searchOperator: "NOTIN"
	});
	return out;
};
const formatTreeMenuItem = (responseObject, treeStructure, catalogObjects, promotedEntities, associatedInquiryTree, wasLazyLoaded) => {
	if (!responseObject) return null;
	const tree = cloneDeep(treeStructure);
	const orderedKeys = [];
	const orderedTreeData = [];
	const treeArr = [];
	processCatalogObjectKeysInOrder(tree, orderedKeys);
	processOrderedTreeData(tree, orderedTreeData);
	processObjectToTree(responseObject, orderedTreeData, orderedKeys, treeArr, catalogObjects, promotedEntities, wasLazyLoaded);
	const displayTree = makeTreeStructure(treeArr, "id", "parentId");
	displayTree["associatedInquiryTree"] = associatedInquiryTree;
	displayTree["wasLazyLoaded"] = wasLazyLoaded;
	return displayTree;
};
const fetchManyToManyChildren = async ({ searchMethod, treeStructure, pageNumber, wasLazyLoaded, executeQueryAdHoc, catalogObjects, promotedEntities }) => {
	const joiningResponse = await executeQueryAdHoc({ data: {
		...searchMethod.data,
		pageNumber
	} }, searchMethod.apiMethodId).catch(() => null);
	if (!joiningResponse || joiningResponse.status !== 200 || !joiningResponse.data?.pageList?.length) return {
		nodes: [],
		hasMore: false
	};
	const items = joiningResponse.data.pageList;
	const hasMore = pageNumber * (searchMethod.pageSize || 50) < joiningResponse.data.total;
	const childFilterElements = [];
	const manyToManyJoiningObject = {
		manyToManyKeys: searchMethod.manyToManyKeys,
		apiMethodId: searchMethod.manyToManyJointEntityApiMethodId
	};
	manyToManyJoiningObject.manyToManyKeys.forEach((mtmKey) => {
		const searchValue = [];
		const formattedPropertyName = toUpperFirstChar(mtmKey.searchNameKey);
		items.forEach((item) => {
			if (item[mtmKey.searchValueKey]) searchValue.push(item[mtmKey.searchValueKey]);
		});
		childFilterElements.push({
			searchField: formattedPropertyName,
			searchValue: searchValue.toString(),
			searchOperator: "IN"
		});
	});
	const entityResponse = await executeQueryAdHoc({ data: getSearchObject(childFilterElements, 1, 50) }, manyToManyJoiningObject.apiMethodId).catch(() => null);
	if (!entityResponse || entityResponse.status !== 200 || !entityResponse.data?.pageList?.length) return {
		nodes: [],
		hasMore
	};
	const joiningEntityCatalogObjectKey = treeStructure?.properties?.joiningEntityCatalogObjectKey;
	const entityItems = entityResponse.data.pageList;
	items.forEach((entityRow) => {
		if (manyToManyJoiningObject && Object.prototype.hasOwnProperty.call(entityRow, joiningEntityCatalogObjectKey)) manyToManyJoiningObject.manyToManyKeys.forEach((mtmKey) => {
			if (entityRow[mtmKey.searchValueKey]) entityRow[joiningEntityCatalogObjectKey] = entityItems.find((item) => item[mtmKey.searchItemIdentifier] === entityRow[mtmKey.searchValueKey]);
		});
	});
	return {
		nodes: items.map((item) => formatTreeMenuItem(item, treeStructure, catalogObjects, promotedEntities, null, wasLazyLoaded)),
		hasMore
	};
};
const fetchLazyChildren = async ({ node, treeStructureArr, executeQueryAdHoc, catalogObjects, promotedEntities, pageNumber = 1, pageSizeOverride = null, filterByBusinessObjectKey = null, targetEntityType = null, inclusionFilter = null, exclusionFilter = null }) => {
	const toArr = (f) => f ? Array.isArray(f) ? f : [f] : [];
	const inclusionList = toArr(inclusionFilter);
	const exclusionList = toArr(exclusionFilter);
	const result = {
		children: [],
		hasMoreChildren: false,
		errorRetrievingChildren: false,
		currentChildPage: pageNumber,
		updatedNodeObj: cloneDeep(node?.nodeObj)
	};
	if (!node?.lazyLoadChildrenArr?.length) return result;
	const parentNodeRefKeys = [];
	const treeStructuresList = [];
	const manyToManyObjectList = [];
	const promises = [];
	const wasLazyLoaded = node?.properties?.lazyLoad;
	const isTargetedFetch = !!filterByBusinessObjectKey && !!targetEntityType;
	node.lazyLoadChildrenArr.forEach((searchMethod) => {
		if (isTargetedFetch && searchMethod.catalogReturnObject !== targetEntityType) return;
		parentNodeRefKeys.push(searchMethod.parentNodeRefKey);
		const childTree = treeStructureArr.find((ts) => ts.properties.catalogReturnObject === searchMethod.catalogReturnObject);
		if (childTree) treeStructuresList.push(childTree);
		let requestData = pageSizeOverride ? {
			...searchMethod.data,
			pageNumber,
			pageSize: pageSizeOverride
		} : {
			...searchMethod.data,
			pageNumber
		};
		if (isTargetedFetch) requestData = {
			...requestData,
			pageSize: 1,
			filterElements: [...requestData.filterElements || [], {
				searchField: "BusinessObjectKey",
				searchValue: filterByBusinessObjectKey,
				searchOperator: "="
			}]
		};
		const includeForThis = inclusionList.find((f) => f.entityType === searchMethod.catalogReturnObject)?.keys;
		const excludeForThis = exclusionList.find((f) => f.entityType === searchMethod.catalogReturnObject)?.keys;
		if (!isTargetedFetch && (includeForThis?.length || excludeForThis?.length)) {
			requestData = {
				...requestData,
				filterElements: getFilters(searchMethod, catalogObjects, {
					includeKeys: includeForThis,
					excludeKeys: excludeForThis
				})
			};
			if (includeForThis?.length) requestData.pageSize = includeForThis.length;
		}
		promises.push(executeQueryAdHoc({ data: requestData }, searchMethod.apiMethodId));
		if (searchMethod.manyToManyJointEntityApiMethodId) manyToManyObjectList.push({
			manyToManyKeys: searchMethod.manyToManyKeys,
			apiMethodId: searchMethod.manyToManyJointEntityApiMethodId
		});
		else manyToManyObjectList.push(null);
	});
	const manyToManyPending = [];
	(await Promise.all(promises.map((p) => p.catch(() => {
		result.errorRetrievingChildren = true;
		return null;
	})))).forEach((response, index) => {
		if (response?.status !== 200 || !response?.data?.pageList?.length) return;
		const isManyToMany = !!manyToManyObjectList[index];
		if (isManyToMany) manyToManyPending.push({
			searchMethod: node.lazyLoadChildrenArr[index],
			treeStructure: treeStructuresList[index],
			wasLazyLoaded
		});
		else if (treeStructuresList[index]) response.data.pageList.forEach((item) => {
			const displayTree = formatTreeMenuItem(item, treeStructuresList[index], catalogObjects, promotedEntities, null, wasLazyLoaded);
			displayTree.parentId = node.id;
			if (displayTree.wasLazyLoaded && !displayTree.properties?.isUsingJointEntityAdditionalProperties && result.children.some((child) => child?.nodeObj?.businessObjectKey && child?.nodeObj?.businessObjectKey === displayTree?.nodeObj?.businessObjectKey)) return;
			result.children.push(displayTree);
		});
		if (!isManyToMany && treeStructuresList[index]) {
			if ((pageSizeOverride || node.lazyLoadChildrenArr[index]?.pageSize || 50) < response.data.total) result.hasMoreChildren = true;
		}
		const parentNodeCatalogObjKey = parentNodeRefKeys[index];
		if (parentNodeCatalogObjKey) result.updatedNodeObj[parentNodeCatalogObjKey] = response.data.pageList;
	});
	(await Promise.all(manyToManyPending.map((entry) => fetchManyToManyChildren({
		searchMethod: entry.searchMethod,
		treeStructure: entry.treeStructure,
		pageNumber,
		wasLazyLoaded: entry.wasLazyLoaded,
		executeQueryAdHoc,
		catalogObjects,
		promotedEntities
	}).catch(() => ({
		nodes: [],
		hasMore: false
	}))))).forEach(({ nodes, hasMore }, index) => {
		const joiningEntityCatalogObjectKey = manyToManyPending[index].treeStructure?.properties?.joiningEntityCatalogObjectKey;
		if (hasMore) result.hasMoreChildren = true;
		nodes.forEach((displayTree) => {
			displayTree.parentId = node.id;
			if (displayTree.wasLazyLoaded && !displayTree.properties?.isUsingJointEntityAdditionalProperties && result.children.some((child) => {
				if (displayTree?.nodeObj) return false;
				return child?.nodeObj?.[joiningEntityCatalogObjectKey]?.businessObjectKey === displayTree?.nodeObj?.[joiningEntityCatalogObjectKey]?.businessObjectKey;
			})) return;
			result.children.push(displayTree);
		});
	});
	return result;
};
const expandAllNodes = (tree, cachedOnly = false) => {
	if (cachedOnly && tree.properties?.lazyLoad && !tree.completedLoadingChildren) return;
	tree.isExpanded = true;
	if (tree?.children) tree.children.forEach((node) => expandAllNodes(node, cachedOnly));
};
const collapseAllNodes = (tree) => {
	tree.isExpanded = false;
	if (tree?.children) tree.children.forEach((node) => collapseAllNodes(node));
};
const findAllParentIds = (menuItems, currentParentNode, allParentIds = []) => {
	if (currentParentNode?.parentId) {
		allParentIds.push(currentParentNode?.parentId);
		findAllParentIds(menuItems, searchTree(menuItems, currentParentNode?.parentId), allParentIds);
	}
	return allParentIds;
};
const formatTreeLabel = (label, obj) => {
	const keys = (label?.split("+"))?.map((field) => field.trim());
	if (keys) {
		const skippableKeys = [];
		const updatedKeys = keys.map((key, index) => {
			if (key.charAt(0) === "\"") {
				skippableKeys.push(index);
				key = key.replace(/"/g, "");
			}
			return key;
		});
		const values = [];
		for (let j = 0; j < keys.length; j++) {
			let property = keys[j];
			if (property) {
				const splitProperties = property.split(".");
				if (splitProperties.length > 1) {
					let constructedValue = null;
					splitProperties.forEach((property) => {
						const matches = property.match(/\[(.*?)\]/);
						let objIndex = null;
						let arrIndex = null;
						if (matches) {
							arrIndex = parseInt(matches[1]);
							objIndex = matches.index;
						}
						if (typeof arrIndex === "number" && objIndex) {
							const formattedProperty = property.substring(0, objIndex);
							if (!constructedValue) {
								if (obj[formattedProperty]) constructedValue = obj[formattedProperty][arrIndex];
							} else if (constructedValue[formattedProperty]) constructedValue = constructedValue[formattedProperty][arrIndex];
						} else if (!constructedValue) constructedValue = obj[property];
						else constructedValue = constructedValue[property];
					});
					if (typeof constructedValue === "boolean" || typeof constructedValue === "number") constructedValue = constructedValue.toString();
					values.push(constructedValue);
					continue;
				}
			}
			let value = obj[property];
			if (typeof value === "boolean" || typeof value === "number") value = value.toString();
			values.push(value);
		}
		let displayName = updatedKeys.join("+");
		for (let k = 0; k < updatedKeys.length; k++) if (!skippableKeys.includes(k)) if (values[k]) displayName = displayName.replace(`${updatedKeys[k]}`, values[k]);
		else displayName = displayName.replace(`${updatedKeys[k]}`, "");
		return displayName.replaceAll("+", " ");
	} else return label;
};
const getDisplayName = (node, obj) => {
	return formatTreeLabel(node.properties["displayName"], obj);
};
const getDisplayDetails = (node, obj) => {
	return formatTreeLabel(node.properties["displayDetails"], obj);
};
const getHeaderTitle = (node, obj) => {
	return formatTreeLabel(node.properties["headerName"], obj);
};
const getNodeIdForRightBorder = (expandedNodeIds, node, parentId) => {
	if (!expandedNodeIds.includes(node?.id)) return node.id;
	if (!expandedNodeIds.includes(parentId)) {
		const foundParentNode = node.children.find((item) => item.id === parentId);
		if (foundParentNode) if (expandedNodeIds.includes(foundParentNode?.parentId)) return parentId;
		else return getNodeIdForRightBorder(expandedNodeIds, foundParentNode, foundParentNode?.parentId);
	} else return parentId;
};
const findNodeById = (tree, id) => {
	let result = null;
	if (tree?.id === id) return tree;
	else {
		if (tree.children) tree.children.some((node) => result = findNodeById(node, id));
		return result;
	}
};
const findNodeByBusinessObjectKey = (tree, businessObjectKey, parent = null, childIndex = -1) => {
	if (!tree) return null;
	if (tree.nodeObj?.businessObjectKey === businessObjectKey) return {
		node: tree,
		parent,
		childIndex
	};
	if (tree.children) for (let i = 0; i < tree.children.length; i++) {
		const match = findNodeByBusinessObjectKey(tree.children[i], businessObjectKey, tree, i);
		if (match) return match;
	}
	return null;
};
const findNodeByBusinessObjectKeyInMenuList = (menuList, businessObjectKey) => {
	if (!menuList?.length) return null;
	for (let i = 0; i < menuList.length; i++) {
		const match = findNodeByBusinessObjectKey(menuList[i], businessObjectKey);
		if (match) return {
			...match,
			menuIndex: i
		};
	}
	return null;
};
const findNodeByIdAndLabel = (tree, id, label) => {
	let result = null;
	if (tree?.id === id && tree?.properties?.label === label) return tree;
	else {
		if (tree.children) tree.children.some((node) => result = findNodeById(node, id, label));
		return result;
	}
};
const findNodesByIdAndLabel = (tree, id, label) => {
	let results = [];
	if (tree?.id === id && tree?.properties?.label === label) results.push(tree);
	if (tree.children) tree.children.forEach((node) => {
		results = results.concat(findNodesByIdAndLabel(node, id, label));
	});
	return results;
};
const updateNodeForStaticGrouping = (displayTree, nodeGroup, nodeChildren, treeList, scopedGroupItemIndexes, groupedItemIndexes, index, item) => {
	const updatedDisplayTree = { ...displayTree };
	if (!checkNodeIsHidden(updatedDisplayTree, item, false)) {
		updatedDisplayTree.children = displayTree.children ? cloneDeep(displayTree.children) : displayTree.children;
		updatedDisplayTree["parentId"] = nodeGroup.id;
		updatedDisplayTree["parentGroupId"] = nodeGroup.id;
		updatedDisplayTree["parentGroupName"] = nodeGroup.properties.label;
		if (updatedDisplayTree.isGroupNode) nodeGroup.children.push(updatedDisplayTree);
		else nodeChildren.push(updatedDisplayTree);
		if (treeList) treeList.push(updatedDisplayTree);
		scopedGroupItemIndexes.add(index);
		groupedItemIndexes.add(index);
	}
};
const processItemForStaticNodeGroup = (nodeGroup, item, groupedItemIndexes, displayTree, index, scopedGroupItemIndexes = /* @__PURE__ */ new Set(), treeList, nodeChildren = []) => {
	if (nodeGroup?.properties?.propertyMapping && nodeGroup?.properties?.jsonLogic) {
		const rule = mapRule(nodeGroup?.properties?.propertyMapping, nodeGroup?.properties?.jsonLogic);
		if (rule && evaluateRule(rule, item, item.properties?.joiningEntityCatalogObjectKey, false)) {
			let itemAdded = false;
			nodeGroup.children.forEach((childGroup) => {
				if (childGroup.isGroupNode) itemAdded = (processItemForStaticNodeGroup(childGroup, item, groupedItemIndexes, displayTree, index, childGroup.children.length ? /* @__PURE__ */ new Set() : scopedGroupItemIndexes, treeList, nodeChildren) || { itemAdded })?.itemAdded;
			});
			if (!itemAdded) {
				updateNodeForStaticGrouping(displayTree, nodeGroup, nodeChildren, treeList, scopedGroupItemIndexes, groupedItemIndexes, index, item);
				itemAdded = true;
			}
		}
	} else if (nodeGroup.isOutlierGroup && !groupedItemIndexes.has(index)) updateNodeForStaticGrouping(displayTree, nodeGroup, nodeChildren, treeList, scopedGroupItemIndexes, groupedItemIndexes, index, item);
	if (treeList && nodeGroup.isGroupNode) {
		if (!treeList.filter((node) => node.isGroupNode).find((eg) => eg.id === nodeGroup.id)) !checkNodeIsHidden(nodeGroup, item, false) && treeList.push(nodeGroup);
	}
	return {
		itemAdded: groupedItemIndexes.has(index),
		nodeChildren
	};
};
const constructStaticNodeGroups = (tree, shouldUseNewId = false) => {
	const nodeGroups = [];
	const groupConfiguration = tree?.properties?.groupConfiguration;
	const groupType = groupConfiguration?.groupType || NodeGroupTypeEnums.Static;
	const hideEmptyGroups = groupConfiguration?.hideEmptyGroups;
	if (groupConfiguration?.enabled && groupConfiguration?.groupings[groupType]?.length) {
		groupConfiguration.groupings[groupType].forEach((grouping) => {
			const orderedGroups = orderByGroupOrder(grouping?.groups);
			const newIdMap = {};
			orderedGroups.forEach((group) => {
				if (shouldUseNewId) newIdMap[group.id] = v4();
				group["children"] = [];
			});
			if (Object.keys(newIdMap).length) orderedGroups.forEach((group) => {
				if (newIdMap[group.id]) group.id = newIdMap[group.id];
				if (newIdMap[group.parentGroupId]) group.parentGroupId = newIdMap[group.parentGroupId];
			});
			if (orderedGroups?.length) {
				const firstGroup = orderedGroups.find((group) => !group.parentGroupId) || orderedGroups[0];
				orderedGroups.shift();
				const displayTree = makeTreeStaticGroupStructure(orderedGroups, "id", "parentGroupId", groupType, hideEmptyGroups);
				const { id, isExpanded, ...firstGroupProperties } = firstGroup;
				const groupNode = new GroupNode({
					id,
					hideEmptyGroups,
					groupType,
					children: Array.isArray(displayTree) ? displayTree : [displayTree],
					isExpanded,
					properties: { ...firstGroupProperties }
				});
				nodeGroups.push(groupNode);
			}
		});
		if (groupConfiguration?.outlier === "group") {
			const outlierGroup = new GroupNode({
				groupType,
				isOutlierGroup: true,
				properties: {
					label: groupConfiguration?.outlierGroupLabel || "Unlabeled Outlier Group",
					icon: groupConfiguration?.outlierIcon
				}
			});
			nodeGroups.push(outlierGroup);
		}
	}
	return nodeGroups;
};
const getOrderedDynamicGroups = (tree, shouldUseNewId = false) => {
	const groupConfiguration = tree?.properties?.groupConfiguration;
	const groupType = groupConfiguration?.groupType || NodeGroupTypeEnums.Dynamic;
	let orderedGroups = [];
	if (groupConfiguration?.enabled && groupConfiguration?.groupings[groupType]?.length) groupConfiguration.groupings[groupType].forEach((grouping) => {
		orderedGroups = orderByGroupOrder(grouping?.groups);
		const newIdMap = {};
		orderedGroups.forEach((group) => {
			if (shouldUseNewId) newIdMap[group.id] = v4();
			group["children"] = [];
		});
		if (Object.keys(newIdMap).length) orderedGroups.forEach((group) => {
			if (newIdMap[group.id]) group.id = newIdMap[group.id];
			if (newIdMap[group.parentGroupId]) group.parentGroupId = newIdMap[group.parentGroupId];
		});
	});
	return orderedGroups;
};
const constructDynamicNodeGroups = (results, tree, shouldUseNewId = false) => {
	let nodeGroups = [];
	const groupConfiguration = tree?.properties?.groupConfiguration;
	const groupType = groupConfiguration?.groupType || NodeGroupTypeEnums.Dynamic;
	if (groupConfiguration?.enabled && groupConfiguration?.groupings[groupType]?.length) groupConfiguration.groupings[groupType].forEach((grouping) => {
		const orderedGroups = orderByGroupOrder(grouping?.groups);
		const newIdMap = {};
		orderedGroups.forEach((group) => {
			if (shouldUseNewId) newIdMap[group.id] = v4();
			group["children"] = [];
		});
		if (Object.keys(newIdMap).length) orderedGroups.forEach((group) => {
			if (newIdMap[group.id]) group.id = newIdMap[group.id];
			if (newIdMap[group.parentGroupId]) group.parentGroupId = newIdMap[group.parentGroupId];
		});
		if (orderedGroups?.length) {
			const isSingleGroup = orderedGroups.length === 1;
			const dynamicTreeStructure = makeDynamicTreeStructure(orderedGroups, "id", "parentGroupId");
			const groupSet = makeDynamicGroupStructures(dynamicTreeStructure, results);
			results.forEach((item, index) => {
				const orderedKeys = [];
				const orderedTreeData = [];
				const treeArr = [];
				const innerGroupList = [];
				processCatalogObjectKeysInOrder(tree, orderedKeys);
				processOrderedTreeData(tree, orderedTreeData);
				processObjectToTree(item, orderedTreeData, orderedKeys, treeArr, null, null, false, innerGroupList);
				const updatedDisplayTree = cloneDeep(makeTreeStructure(treeArr, "id", "parentId"));
				!checkNodeIsHidden(updatedDisplayTree, item, false) && processItemForDynamicNodeGroups(updatedDisplayTree, dynamicTreeStructure, groupSet, groupSet, isSingleGroup);
			});
			groupSet.forEach((group) => updateTreeIds(group, null, v4(), v4(), null));
			nodeGroups = nodeGroups.concat(groupSet);
		}
	});
	return nodeGroups;
};
const getLabelFromProperty = (item, property) => {
	const splitProperties = property.split(".");
	if (splitProperties.length) {
		let constructedValue = null;
		splitProperties.forEach((property) => {
			const matches = property.match(/\[(.*?)\]/);
			let objIndex = null;
			let arrIndex = null;
			if (matches) {
				arrIndex = parseInt(matches[1]);
				objIndex = matches.index;
			}
			if (typeof arrIndex === "number" && objIndex) {
				const formattedProperty = property.substring(0, objIndex);
				if (!constructedValue) {
					if (item[formattedProperty]) constructedValue = item[formattedProperty][arrIndex];
				} else if (constructedValue[formattedProperty]) constructedValue = constructedValue[formattedProperty][arrIndex];
			} else if (!constructedValue) constructedValue = item ? item[property] : "";
			else constructedValue = constructedValue[property];
		});
		return constructedValue;
	}
	return null;
};
const constructBusinessObjectArrFromTree = (node, businessObjects = []) => {
	if (node?.nodeObj) {
		const businessObject = {
			label: "",
			value: "",
			domainObject: ""
		};
		const joiningEntityCatalogObjectKey = node.properties?.joiningEntityCatalogObjectKey;
		const displayName = node.properties?.displayName;
		if (joiningEntityCatalogObjectKey) {
			const jointEntity = node.nodeObj[joiningEntityCatalogObjectKey];
			businessObject.label = formatTreeLabel(displayName, node.nodeObj) || jointEntity?.businessObjectKey;
			businessObject.value = jointEntity?.businessObjectKey;
			businessObject.domainObject = node.properties?.catalogReturnObject;
		} else {
			const entity = node.nodeObj;
			businessObject.label = formatTreeLabel(displayName, node.nodeObj) || entity?.businessObjectKey;
			businessObject.value = entity?.businessObjectKey;
			businessObject.domainObject = node.properties?.catalogReturnObject;
		}
		businessObjects.push(businessObject);
	}
	if (node?.children?.length) node.children.forEach((childNode) => constructBusinessObjectArrFromTree(childNode, businessObjects));
	return businessObjects;
};
const processItemForDynamicNodeGroups = (displayTree, node, groupNodes, previousFilteredGroups = [], isSingleGroup = false) => {
	const { property, id } = node;
	const item = displayTree?.nodeObj;
	const label = property ? getLabelFromProperty(item, property) : null;
	let filteredGroups = [];
	previousFilteredGroups.forEach((group) => {
		if (group) {
			const foundGroups = findNodesByIdAndLabel(group, id, label);
			if (foundGroups.length) filteredGroups = filteredGroups.concat(foundGroups);
		}
	});
	if (filteredGroups.length) if (node?.children?.length) node.children.forEach((child) => processItemForDynamicNodeGroups(displayTree, child, groupNodes, filteredGroups, isSingleGroup));
	else filteredGroups.forEach((filteredGroup) => {
		const matchingGroupNode = findNodeByIdAndLabel(filteredGroup, node.id, label);
		if (matchingGroupNode) {
			displayTree["parentGroupId"] = matchingGroupNode.id;
			matchingGroupNode.children.push(displayTree);
		}
	});
	else if (isSingleGroup) groupNodes.push(displayTree);
	else previousFilteredGroups.forEach((filteredGroup) => {
		if (filteredGroup) {
			displayTree["parentGroupId"] = filteredGroup.id;
			filteredGroup.children.push(displayTree);
		}
	});
};
const orderByGroupOrder = (groups = []) => {
	return orderBy(groups, ["order"], ["asc"]);
};
const updateTreeIds = (node, lastEntityNodeId, newId = v4(), newParentId = v4(), parentGroupName = null) => {
	let entityNodeParentId = lastEntityNodeId;
	if (node) {
		node.id = newId;
		if (node.parentId || node.parentGroupId) {
			node.parentId = newParentId;
			node.parentGroupId = newParentId;
		}
		if (parentGroupName) node["parentGroupName"] = parentGroupName;
		if (!node.isGroupNode && entityNodeParentId) node["entityNodeParentId"] = entityNodeParentId;
		if (!node.isGroupNode) entityNodeParentId = node.id;
	}
	if (node?.children?.length) node.children.forEach((child) => updateTreeIds(child, entityNodeParentId, v4(), newId, parentGroupName));
};
const processGroupNodesAndAddToTreeList = (node, treeList, lastEntityNodeId, item, wasLazyLoaded) => {
	let entityNodeParentId = lastEntityNodeId;
	if (treeList) {
		if (!treeList.find((tree) => tree.id === node.id)) {
			if (!node.isGroupNode && entityNodeParentId) node["entityNodeParentId"] = entityNodeParentId;
			if (!node.isGroupNode) entityNodeParentId = node.id;
			!checkNodeIsHidden(node, item, wasLazyLoaded) && treeList.push(node);
		}
	}
	if (node?.children?.length) node.children.forEach((child) => processGroupNodesAndAddToTreeList(child, treeList, entityNodeParentId, item, wasLazyLoaded));
};
const mapNodeGroupChildren = (nodeGroup, nodeGroupChildren = []) => {
	nodeGroupChildren.forEach((node) => {
		if (nodeGroup.id === node.parentGroupId) nodeGroup.children.push(node);
	});
	if (nodeGroup?.children?.length) nodeGroup.children.forEach((childGroup) => {
		if (childGroup.isGroupNode) mapNodeGroupChildren(childGroup, nodeGroupChildren);
	});
	return nodeGroup;
};
const checkNodeIsHidden = (node, item, wasLazyLoaded = false) => {
	if (!node || node && !Object.keys(node).length) return true;
	let rule = null;
	if (node.isGroupNode) {
		if (node.properties?.hiddenNode?.enabled) {}
	} else if (node.properties?.hiddenNode?.enabled) {
		rule = mapRule(node.properties.hiddenNode.propertyMapping, node.properties.hiddenNode.jsonLogic);
		if (rule && evaluateRule(rule, item, node.properties?.joiningEntityCatalogObjectKey, wasLazyLoaded)) return true;
	}
	return false;
};
const constructPreloadedTree = (treeStructure, pageList, catalogObjects) => {
	if (!pageList) return null;
	let preloadedList = [];
	const tree = cloneDeep(treeStructure);
	if (tree.properties?.groupConfiguration?.enabled && tree.properties?.groupConfiguration.groupType === NodeGroupTypeEnums.Static && tree.properties?.groupConfiguration?.groupings?.static?.length) {
		const topNodeGroups = constructStaticNodeGroups(tree);
		const groupedItemIndexes = /* @__PURE__ */ new Set();
		topNodeGroups.forEach((nodeGroup) => {
			let nodeGroupChildren = [];
			pageList.forEach((item, index) => {
				const orderedKeys = [];
				const orderedTreeData = [];
				const treeArr = [];
				const innerGroupList = [];
				processCatalogObjectKeysInOrder(tree, orderedKeys);
				processOrderedTreeData(tree, orderedTreeData);
				processObjectToTree(item, orderedTreeData, orderedKeys, treeArr, catalogObjects, null, false, innerGroupList);
				const processedItem = processItemForStaticNodeGroup(nodeGroup, item, groupedItemIndexes, makeTreeStructure(treeArr, "id", "parentId"), index, /* @__PURE__ */ new Set());
				nodeGroupChildren = nodeGroupChildren.concat(processedItem?.nodeChildren || []);
			});
			const updatedNodeGroup = mapNodeGroupChildren(nodeGroup, nodeGroupChildren);
			updatedNodeGroup.children.forEach((child) => {
				updateTreeIds(child, null, v4(), updatedNodeGroup.id || v4(), updatedNodeGroup?.properties.label || null);
			});
			preloadedList.push(updatedNodeGroup);
		});
		if (tree.properties?.groupConfiguration?.outlier === NodeGroupOutlierEnums.Individual) pageList.forEach((item, index) => {
			if (!groupedItemIndexes.has(index)) {
				const orderedKeys = [];
				const orderedTreeData = [];
				const treeArr = [];
				processCatalogObjectKeysInOrder(tree, orderedKeys);
				processOrderedTreeData(tree, orderedTreeData);
				processObjectToTree(item, orderedTreeData, orderedKeys, treeArr, null, null, false);
				const displayTree = makeTreeStructure(treeArr, "id", "parentId");
				if (!checkNodeIsHidden(displayTree, item, false)) {
					updateTreeIds(displayTree, null, v4(), v4(), null);
					preloadedList.push(displayTree);
				}
			}
		});
	} else if (tree.properties?.groupConfiguration?.enabled && tree.properties?.groupConfiguration.groupType === NodeGroupTypeEnums.Dynamic && tree.properties?.groupConfiguration?.groupings?.dynamic?.length) {
		const nodeGroups = constructDynamicNodeGroups2(pageList, tree);
		preloadedList = preloadedList.concat(nodeGroups);
	} else pageList.forEach((item) => {
		const orderedKeys = [];
		const orderedTreeData = [];
		const treeArr = [];
		processCatalogObjectKeysInOrder(tree, orderedKeys);
		processOrderedTreeData(tree, orderedTreeData);
		processObjectToTree(item, orderedTreeData, orderedKeys, treeArr);
		const displayTree = makeTreeStructure(treeArr, "id", "parentId");
		!checkNodeIsHidden(displayTree, item, false) && preloadedList.push(displayTree);
	});
	return preloadedList;
};
const CompareGroupByOrder = (a, b) => {
	if (a.order > b.order) return 1;
	if (a.order < b.order) return -1;
	return 0;
};
const CompareSiblingNodes = (a, b) => {
	if (a.hasOwnProperty("isGroupNode") && !b.hasOwnProperty("isGroupNode")) return -1;
	if (!a.hasOwnProperty("isGroupNode") && b.hasOwnProperty("isGroupNode")) return 1;
	if (a.hasOwnProperty("isGroupNode") && b.hasOwnProperty("isGroupNode")) {
		if (a.properties?.order > b.properties?.order) return 1;
		if (a.properties?.order < b.properties?.order) return -1;
	}
	return 0;
};
const GetGroupChildMap = (_map, groupKey) => {
	if (_map[groupKey] === void 0) _map[groupKey] = [];
	return _map[groupKey];
};
const AddGroupToChildMap = (_map, groupKey, groupNode) => {
	let childMap = GetGroupChildMap(_map, groupKey);
	childMap.push(groupNode);
	childMap.sort(CompareGroupByOrder);
};
const createDynamicGroups2 = (_treeConfig, _groupConfig, _item, _curItem, _pList, _siblings, _parentId) => {
	let _groupCreated = false;
	if (_pList.length > 0) {
		let tmpProp = _pList[0];
		if (_curItem.hasOwnProperty(tmpProp)) {
			let newItem = _curItem[tmpProp];
			if (_pList.length > 1) {
				if (Array.isArray(newItem)) for (let i = 0, numOfItems = newItem.length; i < numOfItems; i++) {
					let aGroupWasCreated = createDynamicGroups2(_treeConfig, _groupConfig, _item, newItem[i], _pList.slice(1), _siblings, _parentId);
					_groupCreated = aGroupWasCreated ? aGroupWasCreated : _groupCreated;
				}
				else if (typeof newItem === "object" && newItem !== null) {
					let aGroupWasCreated = createDynamicGroups2(_treeConfig, _groupConfig, _item, newItem, _pList.slice(1), _siblings, _parentId);
					_groupCreated = aGroupWasCreated ? aGroupWasCreated : _groupCreated;
				}
			} else if (typeof newItem !== "object" && newItem !== null && newItem !== "") {
				let groupName = newItem.toString();
				let groupNode = null;
				for (let siblingIdx = 0, numOfSiblings = _siblings.length; siblingIdx < numOfSiblings; siblingIdx++) {
					let sibling = _siblings[siblingIdx];
					if (sibling.hasOwnProperty("isGroupNode") && sibling.isGroupNode === true) {
						if (sibling.properties.label === groupName) {
							groupNode = sibling;
							break;
						}
					}
				}
				if (groupNode == null) {
					groupNode = new GroupNode({
						id: `${v4()}`,
						groupType: NodeGroupTypeEnums.Dynamic,
						children: [],
						parentGroupId: _parentId,
						parentId: _parentId,
						isExpanded: _groupConfig.isExpanded,
						properties: {
							label: groupName,
							propertyIsCustom: _groupConfig.propertyIsCustom,
							propertyKey: _groupConfig.property,
							order: _groupConfig.order
						}
					});
					_siblings.push(groupNode);
				}
				_groupCreated = true;
				let subGroupWasCreated = false;
				for (let subGroupIdx = 0, numOfSubGroups = _groupConfig.children.length; subGroupIdx < numOfSubGroups; subGroupIdx++) {
					let subGroupConfig = _groupConfig.children[subGroupIdx];
					let subGroupCreated = createDynamicGroups2(_treeConfig, subGroupConfig, _item, _item, subGroupConfig.property ? subGroupConfig.property.split(".") : [], groupNode.children, groupNode.id);
					subGroupWasCreated = subGroupCreated ? subGroupCreated : subGroupWasCreated;
				}
				if (!subGroupWasCreated) {
					let tmpNode = cloneDeep(_treeConfig);
					processObjIndex(tmpNode, _item, null, groupNode.id, null, null, false);
					groupNode.children.push(tmpNode);
					let newChildNodes = [];
					for (let childNodeIdx = 0, numOfChildNodes = tmpNode.children.length; childNodeIdx < numOfChildNodes; childNodeIdx++) {
						let childConfigNode = tmpNode.children[childNodeIdx];
						let propToGetRecords = childConfigNode.properties.catalogObjectKey;
						if (propToGetRecords && propToGetRecords != null && _item.hasOwnProperty(propToGetRecords)) {
							let newResultSet = _item[propToGetRecords];
							if (newResultSet && newResultSet != null) if (Array.isArray(newResultSet)) newChildNodes.push(...constructDynamicNodeGroups2(newResultSet, childConfigNode, tmpNode.id));
							else {
								[].push(newResultSet);
								newChildNodes.push(...constructDynamicNodeGroups2(newResultSet, childConfigNode, tmpNode.id));
							}
						}
					}
					tmpNode.children = newChildNodes;
				}
				groupNode.children.sort(CompareSiblingNodes);
			}
		}
	}
	return _groupCreated;
};
const constructDynamicGroupConfigTrees2 = (configNode) => {
	let topLevelConfigGroupNodes = [];
	const groupConfiguration = configNode?.properties?.groupConfiguration;
	const groupType = groupConfiguration?.groupType || NodeGroupTypeEnums.Dynamic;
	if (groupConfiguration?.enabled && groupConfiguration?.groupings[groupType]?.length) {
		let dynamicGroupings = groupConfiguration.groupings[groupType];
		for (let groupingIdx = 0, numOfGroupings = dynamicGroupings.length; groupingIdx < numOfGroupings; groupingIdx++) {
			let grouping = dynamicGroupings[groupingIdx];
			if (grouping.groups === void 0 || grouping.groups === null) continue;
			let groupChildMap = {};
			for (let groupIdx = 0, numOfGroups = grouping.groups.length; groupIdx < numOfGroups; groupIdx++) {
				let group = grouping.groups[groupIdx];
				group["children"] = GetGroupChildMap(groupChildMap, group.id);
				if (group.parentGroupId === void 0 || group.parentGroupId === null) topLevelConfigGroupNodes.push(group);
				else AddGroupToChildMap(groupChildMap, group.parentGroupId, group);
			}
		}
	}
	for (let configIdx = 0, numOfChildConfigNodes = configNode.children.length; configIdx < numOfChildConfigNodes; configIdx++) {
		let childConfigNode = configNode.children[configIdx];
		constructDynamicGroupConfigTrees2(childConfigNode);
	}
	configNode.groupConfigTrees = topLevelConfigGroupNodes;
};
const constructDynamicNodeGroups2 = (results, configNode, parentId = null) => {
	let levelNodes = [];
	if (!configNode.groupConfigTrees) constructDynamicGroupConfigTrees2(configNode);
	for (let rIdx = 0, numOfResults = results.length; rIdx < numOfResults; rIdx++) {
		let item = results[rIdx];
		let groupCreated = false;
		for (let ctlIdx = 0, numOfGroupConfigTrees = configNode.groupConfigTrees.length; ctlIdx < numOfGroupConfigTrees; ctlIdx++) {
			let groupConfigNode = configNode.groupConfigTrees[ctlIdx];
			let aGroupWasCreated = createDynamicGroups2(configNode, groupConfigNode, item, item, groupConfigNode.property ? groupConfigNode.property.split(".") : [], levelNodes, parentId);
			groupCreated = aGroupWasCreated ? aGroupWasCreated : groupCreated;
		}
		if (!groupCreated) {
			let tmpNode = cloneDeep(configNode);
			processObjIndex(tmpNode, item, null, parentId, null, null, false);
			levelNodes.push(tmpNode);
			let newChildNodes = [];
			for (let childNodeIdx = 0, numOfChildNodes = tmpNode.children.length; childNodeIdx < numOfChildNodes; childNodeIdx++) {
				let childConfigNode = tmpNode.children[childNodeIdx];
				let propToGetRecords = childConfigNode.properties.catalogObjectKey;
				if (propToGetRecords && propToGetRecords != null && item.hasOwnProperty(propToGetRecords)) {
					let newResultSet = item[propToGetRecords];
					if (newResultSet && newResultSet != null) if (Array.isArray(newResultSet)) newChildNodes.push(...constructDynamicNodeGroups2(newResultSet, childConfigNode, tmpNode.id));
					else {
						[].push(newResultSet);
						newChildNodes.push(...constructDynamicNodeGroups2(newResultSet, childConfigNode, tmpNode.id));
					}
				}
			}
			tmpNode.children = newChildNodes;
		}
	}
	levelNodes.sort(CompareSiblingNodes);
	return levelNodes;
};
const transformMenuPageTree = (node) => {
	if (!node?.menuItemInstance?.isActive) return null;
	const parameters = node.menuItemInstance?.parameters && JSON.parse(node.menuItemInstance.parameters);
	const label = node.title || "";
	const expanded = parameters?.defaultDisplay === "expanded";
	const updatedNode = {
		id: node.menuStructureId,
		parentId: node.parentId,
		isExpanded: expanded,
		properties: {
			defaultIcon: {
				type: "",
				name: parameters?.FluentIcon,
				color: ""
			},
			nodeLabel: label,
			nodeSubLabel: "",
			itemCount: parameters?.itemCount ?? node.menuItemInstance?.itemCount ?? null,
			page: {
				id: parameters?.PageId,
				entity: { entityName: parameters?.entityName },
				pbiReportCode: parameters?.pbiReportCode,
				udpTagId: parameters?.udpTagId,
				queryId: parameters?.queryId,
				inquiryTreeId: parameters?.InquiryTreeId,
				requiredFieldMapping: parameters?.requiredFieldMapping
			},
			aggregateThresholdId: parameters?.aggregateThresholdId || ""
		},
		children: []
	};
	for (const child of node.menuItemInstanceStructures) {
		const updatedChild = transformMenuPageTree(child);
		if (updatedChild) updatedNode.children.push(updatedChild);
	}
	return updatedNode;
};
const mapNodeObjValuesToSearchParameters = (nodeObj, aggregateThresholdParamMappings) => {
	if (!aggregateThresholdParamMappings || !nodeObj) return {};
	const mappings = { ...aggregateThresholdParamMappings };
	Object.keys(mappings).forEach((key) => {
		const nodeObjKey = mappings[key];
		if (nodeObjKey) mappings[key] = nodeObj[nodeObjKey] || "";
	});
	return mappings;
};
const getSearchValueString = (nodeObj, searchIdentifier) => {
	const searchIdentifiers = searchIdentifier.split(",");
	const searchValues = [];
	searchIdentifiers.forEach((searchIdentifier) => {
		searchValues.push(nodeObj[searchIdentifier]);
	});
	return searchValues.toString();
};
//#endregion
export { checkNodeIsHidden, collapseAllNodes, collectChildVaryingKeysByType, constructBusinessObjectArrFromTree, constructDynamicNodeGroups, constructDynamicNodeGroups2, constructPreloadedTree, constructStaticNodeGroups, deleteNode, deleteNodeAndChildren, expandAllNodes, fetchCountsByType, fetchLazyChildren, fetchManyToManyChildren, findAllParentIds, findLastNode, findNodeByBusinessObjectKey, findNodeByBusinessObjectKeyInMenuList, findNodeById, findNodeByIdAndLabel, findNodesByIdAndLabel, formatTreeLabel, formatTreeMenuItem, getAllChildrenNodesToDelete, getDisplayDetails, getDisplayName, getFilters, getHeaderTitle, getIconFromName, getLazyLoadChildrenArr, getNodeIdForRightBorder, getOrderedDynamicGroups, getSearchValueString, getVaryingChildKey, keysByTypeToFilterArray, makeDynamicGroupStructures, makeDynamicTreeStructure, makeTreeStaticGroupStructure, makeTreeStructure, mapNodeGroupChildren, mapNodeObjValuesToSearchParameters, processCatalogObjectKeysInOrder, processItemForDynamicNodeGroups, processItemForStaticNodeGroup, processObjIndex, processObjectToTree, processOrderedTreeData, processReferences, searchTree, transformMenuPageTree, updateTreeIds };

//# sourceMappingURL=TreeUtilities.mjs.map