import {
  validateTreeLimits,
  TREE_LIMITS
} from "@open-mercato/shared/lib/query/advanced-filter-tree";
let addedAtCounter = 0;
function nextAddedAt() {
  addedAtCounter += 1;
  return addedAtCounter;
}
function emptyRule(defaultField, defaultOperator) {
  return {
    id: crypto.randomUUID(),
    type: "rule",
    field: defaultField ?? "",
    operator: defaultOperator ?? "contains",
    value: "",
    addedAt: nextAddedAt()
  };
}
function emptyGroup(defaultField, defaultOperator) {
  return {
    id: crypto.randomUUID(),
    type: "group",
    combinator: "and",
    children: [emptyRule(defaultField, defaultOperator)],
    addedAt: nextAddedAt()
  };
}
function findMaxAddedAtNode(group) {
  let best = null;
  function walk(g) {
    g.children.forEach((c, idx) => {
      const a = c.addedAt;
      if (typeof a === "number") {
        if (!best || a > best.addedAt) best = { parent: g, idx, addedAt: a };
      }
      if (c.type === "group") walk(c);
    });
  }
  walk(group);
  return best;
}
function findGroupAndDepth(root, id, depth = 1) {
  if (root.id === id) return { group: root, depth };
  for (const child of root.children) {
    if (child.type === "group") {
      const r = findGroupAndDepth(child, id, depth + 1);
      if (r) return r;
    }
  }
  return null;
}
function countRules(group) {
  let n = 0;
  for (const c of group.children) {
    if (c.type === "rule") n += 1;
    else n += countRules(c);
  }
  return n;
}
function treeReducer(state, action) {
  if (action.type === "replaceRoot") {
    const next2 = { root: action.root };
    const v2 = validateTreeLimits(next2);
    return v2.ok ? next2 : state;
  }
  const next = JSON.parse(JSON.stringify(state));
  if (action.type === "removeLast") {
    const found = findMaxAddedAtNode(next.root);
    if (!found) return state;
    found.parent.children.splice(found.idx, 1);
    const v2 = validateTreeLimits(next);
    return v2.ok ? next : state;
  }
  let mutated = false;
  function apply(group) {
    switch (action.type) {
      case "addRule":
        if (group.id === action.groupId) {
          group.children.push(emptyRule(action.defaultField, action.defaultOperator));
          return true;
        }
        break;
      case "addGroup":
        if (group.id === action.groupId) {
          group.children.push(emptyGroup(action.defaultField, action.defaultOperator));
          return true;
        }
        break;
      case "updateGroupCombinator":
        if (group.id === action.groupId) {
          group.combinator = action.combinator;
          return true;
        }
        break;
      case "removeNode": {
        const idx = group.children.findIndex((c) => c.id === action.nodeId);
        if (idx >= 0) {
          group.children.splice(idx, 1);
          return true;
        }
        break;
      }
      case "updateRule":
        for (const c of group.children) {
          if (c.type === "rule" && c.id === action.ruleId) {
            Object.assign(c, action.updates);
            return true;
          }
        }
        break;
      case "reorderChildren":
        if (group.id === action.groupId) {
          const arr = group.children;
          if (action.fromIdx >= 0 && action.fromIdx < arr.length && action.toIdx >= 0 && action.toIdx < arr.length && action.fromIdx !== action.toIdx) {
            const [moved] = arr.splice(action.fromIdx, 1);
            arr.splice(action.toIdx, 0, moved);
            return true;
          }
        }
        break;
    }
    for (const c of group.children) {
      if (c.type === "group" && apply(c)) return true;
    }
    return false;
  }
  mutated = apply(next.root);
  if (!mutated) return state;
  const v = validateTreeLimits(next);
  if (!v.ok) return state;
  return next;
}
function canAddRule(tree, groupId) {
  const found = findGroupAndDepth(tree.root, groupId);
  if (!found) return false;
  if (found.group.children.length >= TREE_LIMITS.maxChildrenPerGroup) return false;
  if (countRules(tree.root) >= TREE_LIMITS.maxTotalRules) return false;
  return true;
}
function canAddGroup(tree, groupId) {
  const found = findGroupAndDepth(tree.root, groupId);
  if (!found) return false;
  if (found.group.children.length >= TREE_LIMITS.maxChildrenPerGroup) return false;
  if (found.depth >= TREE_LIMITS.maxGroupLevel) return false;
  if (countRules(tree.root) >= TREE_LIMITS.maxTotalRules) return false;
  return true;
}
function getGroupDepth(tree, groupId) {
  const found = findGroupAndDepth(tree.root, groupId);
  return found?.depth ?? null;
}
export {
  canAddGroup,
  canAddRule,
  getGroupDepth,
  treeReducer
};
//# sourceMappingURL=treeReducer.js.map
