/**
 * Shallow JSON-record diff utilities for UI summary chips.
 *
 * <p>Lives in `src/lib` (not in a route file) so that callers beyond the
 * record-draft ReviewDrawer can reuse it — RecordHistoryDrawer, audit row
 * summary, future audit-trail tooltips. Pre-emptive DRY: surfaced during
 * the 2026-05-14 eng review of MR !186.
 *
 * <p>Shallow on purpose: ordinis business records are flat-ish at the top
 * level (business fields, no deep object trees that would require a real
 * structural diff). Nested-object changes are reported as a single
 * "changed" entry on the outer key. Good enough for "what's the gist" UI
 * chips. For full schema-level diff with line-by-line highlighting, see
 * `ChangelogDiffModal` + its backend `summary.added/removed/changed`
 * payload.
 *
 * <p>Equality is checked via `JSON.stringify`. Order-sensitive — relies on
 * V8/JSC preserving insertion order for plain objects (true on every
 * modern runtime ordinis ships against). Sufficient for record data which
 * is always object-literal serialized; not safe for Map/Set/Date/RegExp,
 * none of which appear in record payloads.
 */

export type ShallowDiffSummary = {
  added: string[]
  removed: string[]
  changed: string[]
}

/**
 * @returns null when both inputs are null/undefined (e.g. CLOSE op draft
 *          with no live record). Caller can skip rendering entirely.
 *          Otherwise: per-bucket key lists, never null.
 */
export function shallowDiffSummary(
  before: Record<string, unknown> | null | undefined,
  after: Record<string, unknown> | null | undefined,
): ShallowDiffSummary | null {
  if (!before && !after) return null
  const b = before ?? {}
  const a = after ?? {}
  const added: string[] = []
  const removed: string[] = []
  const changed: string[] = []
  for (const k of Object.keys(a)) {
    if (!(k in b)) {
      added.push(k)
    } else if (JSON.stringify(a[k]) !== JSON.stringify(b[k])) {
      changed.push(k)
    }
  }
  for (const k of Object.keys(b)) {
    if (!(k in a)) removed.push(k)
  }
  return { added, removed, changed }
}

/** Convenience: empty when all three buckets are empty. */
export function isEmptyDiffSummary(s: ShallowDiffSummary): boolean {
  return s.added.length === 0 && s.removed.length === 0 && s.changed.length === 0
}
