"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var blueprintDiff_exports = {};
__export(blueprintDiff_exports, {
  diffBlueprints: () => diffBlueprints
});
module.exports = __toCommonJS(blueprintDiff_exports);
var import_fingerprint = require("./fingerprint");
const TRANSIENT_ROLES = /* @__PURE__ */ new Set(["status", "alert", "log", "marquee"]);
function truncate(s, max) {
  return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
}
function isTransient(el) {
  return TRANSIENT_ROLES.has(el.role);
}
function indexBlueprint(bp) {
  const sections = /* @__PURE__ */ new Map();
  const elementsByLogical = /* @__PURE__ */ new Map();
  const elementsByStableId = /* @__PURE__ */ new Map();
  const elementsByTestId = /* @__PURE__ */ new Map();
  const repeatingByLogical = /* @__PURE__ */ new Map();
  const repeatingByStableId = /* @__PURE__ */ new Map();
  const repeatingByTestId = /* @__PURE__ */ new Map();
  const ambiguousElementStableIds = /* @__PURE__ */ new Set();
  const ambiguousElementTestIds = /* @__PURE__ */ new Set();
  const ambiguousRepeatingStableIds = /* @__PURE__ */ new Set();
  const ambiguousRepeatingTestIds = /* @__PURE__ */ new Set();
  function setOnce(map, key, value, ambiguous) {
    if (map.has(key))
      ambiguous.add(key);
    else
      map.set(key, value);
  }
  for (const section of bp.sections) {
    sections.set(section.name, section);
    for (const el of section.elements) {
      const entry = { section, element: el };
      elementsByLogical.set(`${section.name}::${el.logicalName}`, entry);
      if (el.stableId !== null)
        setOnce(elementsByStableId, `${section.name}::${el.stableId}`, entry, ambiguousElementStableIds);
      if (el.testId !== null)
        setOnce(elementsByTestId, `${section.name}::${el.testId}`, entry, ambiguousElementTestIds);
    }
    for (const rep of section.repeatingElements) {
      const entry = { section, element: rep };
      repeatingByLogical.set(`${section.name}::${rep.logicalName}`, entry);
      if (rep.stableId !== null)
        setOnce(repeatingByStableId, `${section.name}::${rep.stableId}`, entry, ambiguousRepeatingStableIds);
      if (rep.testId !== null)
        setOnce(repeatingByTestId, `${section.name}::${rep.testId}`, entry, ambiguousRepeatingTestIds);
    }
  }
  return {
    sections,
    elementsByLogical,
    elementsByStableId,
    elementsByTestId,
    repeatingByLogical,
    repeatingByStableId,
    repeatingByTestId,
    ambiguousElementStableIds,
    ambiguousElementTestIds,
    ambiguousRepeatingStableIds,
    ambiguousRepeatingTestIds
  };
}
function findCounterpart(el, section, index) {
  const byLogical = index.elementsByLogical.get(`${section.name}::${el.logicalName}`);
  if (byLogical) return byLogical;
  if (el.stableId !== null) {
    const key = `${section.name}::${el.stableId}`;
    if (!index.ambiguousElementStableIds.has(key)) {
      const bySid = index.elementsByStableId.get(key);
      if (bySid) return bySid;
    }
  }
  if (el.testId !== null) {
    const key = `${section.name}::${el.testId}`;
    if (!index.ambiguousElementTestIds.has(key)) {
      const byTid = index.elementsByTestId.get(key);
      if (byTid) return byTid;
    }
  }
  return null;
}
function findRepeatingCounterpart(rep, section, index) {
  const byLogical = index.repeatingByLogical.get(`${section.name}::${rep.logicalName}`);
  if (byLogical) return byLogical;
  if (rep.stableId !== null) {
    const key = `${section.name}::${rep.stableId}`;
    if (!index.ambiguousRepeatingStableIds.has(key)) {
      const bySid = index.repeatingByStableId.get(key);
      if (bySid) return bySid;
    }
  }
  if (rep.testId !== null) {
    const key = `${section.name}::${rep.testId}`;
    if (!index.ambiguousRepeatingTestIds.has(key)) {
      const byTid = index.repeatingByTestId.get(key);
      if (byTid) return byTid;
    }
  }
  return null;
}
function elementRef(section, el) {
  return {
    logicalName: el.logicalName,
    sectionLogicalName: section.name,
    role: el.role,
    accessibleName: el.accessibleName
  };
}
function diffBlueprints(before, after) {
  const A = indexBlueprint(before);
  const B = indexBlueprint(after);
  const delta = {
    hasStructuralChange: false,
    sectionsAdded: [],
    sectionsRemoved: [],
    elementsAdded: [],
    elementsRemoved: [],
    repeatingCountChanges: [],
    repeatingItemsChanged: [],
    textChanges: [],
    enrichmentChanges: []
  };
  if (before.url !== after.url)
    delta.urlChange = { before: before.url, after: after.url };
  if (before.pageHash !== after.pageHash)
    delta.pageHashChange = { before: before.pageHash, after: after.pageHash };
  for (const name of B.sections.keys())
    if (!A.sections.has(name)) delta.sectionsAdded.push({ sectionLogicalName: name });
  for (const name of A.sections.keys())
    if (!B.sections.has(name)) delta.sectionsRemoved.push({ sectionLogicalName: name });
  for (const { section, element } of B.elementsByLogical.values()) {
    if (findCounterpart(element, section, A)) continue;
    delta.elementsAdded.push({
      ...elementRef(section, element),
      kind: isTransient(element) ? "transient" : "persistent"
    });
  }
  for (const { section, element } of A.elementsByLogical.values()) {
    if (findCounterpart(element, section, B)) continue;
    delta.elementsRemoved.push(elementRef(section, element));
  }
  for (const { section: sBefore, element: elBefore } of A.elementsByLogical.values()) {
    const matched = findCounterpart(elBefore, sBefore, B);
    if (!matched) continue;
    const elAfter = matched.element;
    const tA = elBefore.accessibleName.trim();
    const tB = elAfter.accessibleName.trim();
    if (tA !== tB) {
      delta.textChanges.push({
        logicalName: elBefore.logicalName,
        sectionLogicalName: sBefore.name,
        role: elAfter.role,
        accessibleName: elAfter.accessibleName,
        before: truncate(tA, 200),
        after: truncate(tB, 200)
      });
    }
    if (elBefore.mutability !== elAfter.mutability) {
      delta.enrichmentChanges.push({
        logicalName: elBefore.logicalName,
        sectionLogicalName: sBefore.name,
        field: "mutability",
        before: elBefore.mutability,
        after: elAfter.mutability
      });
    }
    if (elBefore.widgetType !== elAfter.widgetType) {
      delta.enrichmentChanges.push({
        logicalName: elBefore.logicalName,
        sectionLogicalName: sBefore.name,
        field: "widgetType",
        before: elBefore.widgetType,
        after: elAfter.widgetType
      });
    }
  }
  for (const { section, element: repB } of B.repeatingByLogical.values()) {
    const matched = findRepeatingCounterpart(repB, section, A);
    if (!matched) {
      delta.elementsAdded.push({
        logicalName: repB.logicalName,
        sectionLogicalName: section.name,
        role: repB.role,
        accessibleName: repB.accessibleNameTemplate,
        kind: "persistent"
      });
      continue;
    }
    const repA = matched.element;
    if (repA.items.length !== repB.items.length) {
      delta.repeatingCountChanges.push({
        logicalName: repB.logicalName,
        sectionLogicalName: section.name,
        role: repB.role,
        accessibleNameTemplate: repB.accessibleNameTemplate,
        before: repA.items.length,
        after: repB.items.length,
        delta: repB.items.length - repA.items.length
      });
    } else {
      const aKeys = new Set(repA.items.map((i) => (0, import_fingerprint.canonicalJson)(i.parameters)));
      const bKeys = new Set(repB.items.map((i) => (0, import_fingerprint.canonicalJson)(i.parameters)));
      let changed = aKeys.size !== bKeys.size;
      if (!changed) {
        for (const k of aKeys) if (!bKeys.has(k)) {
          changed = true;
          break;
        }
      }
      if (changed) {
        delta.repeatingItemsChanged.push({
          logicalName: repB.logicalName,
          sectionLogicalName: section.name,
          changed: true
        });
      }
    }
  }
  for (const { section, element: repA } of A.repeatingByLogical.values()) {
    if (findRepeatingCounterpart(repA, section, B)) continue;
    delta.elementsRemoved.push({
      logicalName: repA.logicalName,
      sectionLogicalName: section.name,
      role: repA.role,
      accessibleName: repA.accessibleNameTemplate
    });
  }
  delta.hasStructuralChange = delta.sectionsAdded.length > 0 || delta.sectionsRemoved.length > 0 || delta.elementsAdded.length > 0 || delta.elementsRemoved.length > 0 || delta.repeatingCountChanges.length > 0 || delta.repeatingItemsChanged.length > 0;
  return delta;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  diffBlueprints
});
