/**
 * squash-integrity.ts — Pure detection of the prod-breaking condition the
 * squash toolchain used to be BLIND to.
 *
 * `status`/`squash` already compute `branch-only = local − reference` (extra
 * local migrations, safe to consolidate). The dangerous *inverse* was never
 * checked: a migration that EXISTS on the reference branch (e.g. `origin/main`)
 * but is MISSING from the current working tree — deleted or renamed locally by a
 * manual "brutal re-baseline". A plain merge then removes an already-applied
 * migration from production, and everything downstream breaks.
 *
 * This module is the single source of truth for that diff. It is PURE (no git,
 * no fs) — the caller supplies the reference paths (from `git ls-tree`) and the
 * present paths (from disk / `git ls-files`); the file-system reads live in
 * squash/execute.ts and status/execute.ts.
 */

/**
 * Reduce any migration file path to its comparable migration key:
 * the file's base name without the `.cs` / `.Designer.cs` suffix.
 * Returns `null` for non-migration files (snapshots, non-`.cs`) so they never
 * pollute the diff. A migration and its `.Designer.cs` sidecar collapse to the
 * same key — so a reference whose `.Designer.cs` lingers but whose migration is
 * present is NOT reported missing, and vice-versa.
 */
export function migrationKey(filePath: string): string | null {
  const base = filePath.replace(/\\/g, '/').split('/').pop();
  if (!base || !base.endsWith('.cs')) return null;
  if (base.endsWith('ModelSnapshot.cs')) return null;
  return base.replace(/\.Designer\.cs$/i, '').replace(/\.cs$/i, '');
}

/**
 * The reference-branch migrations that are ABSENT from the working tree.
 *
 * Returns the sorted, de-duplicated set of migration keys present in
 * `referencePaths` but not in `presentPaths`. An empty array means safe: every
 * migration the reference branch holds is still in the working tree.
 *
 * A non-empty result is the exact "casse-prod" signal — these migrations would
 * be dropped from production at merge. The caller (squash) must REFUSE by
 * default; only a deliberate, logged `-BruteForce` re-baseline may proceed.
 */
export function findMissingReferenceMigrations(
  referencePaths: string[],
  presentPaths: string[],
): string[] {
  const present = new Set(
    presentPaths.map(migrationKey).filter((k): k is string => k !== null),
  );
  const reference = new Set(
    referencePaths.map(migrationKey).filter((k): k is string => k !== null),
  );
  return Array.from(reference)
    .filter((k) => !present.has(k))
    .sort();
}

/** The reference-branch migration keys (names), sorted + de-duplicated. The 🔒 "parent / untouchable" list shown before any squash. */
export function referenceMigrationNames(referencePaths: string[]): string[] {
  const names = new Set(
    referencePaths.map(migrationKey).filter((k): k is string => k !== null),
  );
  return Array.from(names).sort();
}
