// src/lib/spec/audit/run.ts — the pure audit runner. Applies the check registry
// over the flattened CHECKLIST and computes a score. Items with no registry
// entry are "manual" (kept in the manual checklist); na/manual are excluded from
// the score denominator. Deterministic, no I/O — drives the bulk of the tests.
import { CHECKLIST } from "@/lib/spec/checklist-data";
import type { SpecItem } from "@/lib/spec/types";
import { CHECKS, type CheckContext, type CheckStatus } from "./checks";
import type { SiteSnapshot } from "./snapshot";

export type AuditResultStatus = CheckStatus | "manual";

export type AuditResultRow = {
  itemId: string;
  status: AuditResultStatus;
  detail: string;
};

export type AuditResult = {
  ranAt: string;
  score: number;
  results: AuditResultRow[];
};

/** All CHECKLIST items, flattened across categories (display order preserved). */
export const CHECKLIST_FLAT: SpecItem[] = CHECKLIST.flatMap((c) => c.items);

/**
 * Run the audit. For each item, apply its registry check or mark it "manual".
 * Score = round(100 × pass / (pass + fail + warn)) over auto-checked items;
 * `na` and `manual` are excluded from the denominator. Empty denominator → 0.
 */
export function runSiteAudit(
  snapshot: SiteSnapshot,
  ctx: CheckContext,
  items: SpecItem[] = CHECKLIST_FLAT,
): AuditResult {
  const results: AuditResultRow[] = items.map((item) => {
    const check = CHECKS[item.id];
    if (!check) return { itemId: item.id, status: "manual", detail: "" };
    const { status, detail } = check(snapshot, ctx);
    return { itemId: item.id, status, detail };
  });

  let pass = 0;
  let denom = 0;
  for (const r of results) {
    if (r.status === "pass") {
      pass++;
      denom++;
    } else if (r.status === "fail" || r.status === "warn") {
      denom++;
    }
  }
  const score = denom === 0 ? 0 : Math.round((100 * pass) / denom);

  return { ranAt: new Date().toISOString(), score, results };
}
