// Utility: clean and normalize text
const cleanText = (text) =>
  String(text || "")
    .toLowerCase()
    .replace(/<img[^>]*>/gi, "") // remove <img> tags
    .replace(/&nbsp;/gi, " ") // replace non-breaking space
    .replace(/<[^>]*>/g, "") // remove any other HTML tags
    .replace(/[,\.]/g, "") // remove commas and periods
    .replace(/([a-zA-Z])(\d)/g, "$1 $2") // split letters & digits
    .replace(/(\d)([a-zA-Z])/g, "$1 $2")
    .replace(/\s+/g, " ") // collapse spaces
    .trim()
    .replace(/\bcomma\b\s*\bfull\s*stop\b/g, "comma fullstop");

// Normalize the condition parts similarly to original code logic
const normalizeConditionParts = (rawConditions) => {
  let parts = [];

  if (typeof rawConditions === "string") {
    parts = rawConditions.split(",");
  } else if (Array.isArray(rawConditions)) {
    parts = rawConditions;
  } else {
    // if conditions is null, undefined, object etc.
    parts = [];
  }

  const set1 = [];
  const set2 = [];
  let currentSet = null;

  for (let part of parts) {
    const cleaned = cleanText(part);
    if (cleaned === "condition set 1") {
      currentSet = set1;
      continue;
    }
    if (cleaned === "condition set 2") {
      currentSet = set2;
      continue;
    }
    if (currentSet) currentSet.push(cleaned);
  }

  set1.sort();
  set2.sort();

  return { set1, set2 };
};

// Normalize actions (handle string or array)
const normalizeActions = (actions) => {
  if (Array.isArray(actions)) {
    return actions
      .map((action) =>
        Object.values(action)
          .map((v) => cleanText(v))
          .join(" ")
      )
      .sort()
      .join(",");
  } else if (typeof actions === "string") {
    return actions
      .split(",")
      .map((a) => cleanText(a))
      .sort()
      .join(",");
  }
  return "";
};

// Main normalized signature function combining conditions, actions, and operator
const getRuleSignatureNormalized = (rule) => {
  const rawConditions = rule.summary?.conditions || rule.conditions || "";
  const rawActions = rule.summary?.actions || rule.actions || "";
  const operator = rule.operator || "";

  const { set1, set2 } = normalizeConditionParts(rawConditions);
  const normalizedActions = normalizeActions(rawActions);
  const normalizedOperator = cleanText(operator);

  // The signature should consider the fact conditions might be interchangeable
  // between set1 and set2 (commutative)
  const key1 = JSON.stringify({ set1, set2, actions: normalizedActions, operator: normalizedOperator });
  const key2 = JSON.stringify({ set1: set2, set2: set1, actions: normalizedActions, operator: normalizedOperator });

  // Return lexicographically smallest key for commutative sets
  return key1 < key2 ? key1 : key2;
};

// Group duplicates by normalized signature
const groupDuplicates = (rules) => {
  const groups = {};
  rules
    .filter((rule) => rule.active === "true" || rule.active === true) // handle boolean or string "true"
    .forEach((rule) => {
      const signature = getRuleSignatureNormalized(rule);
      if (!groups[signature]) groups[signature] = [];
      groups[signature].push(rule);
    });

  return Object.values(groups);
};



in this it does compares rule name and description