/**
 * Render the per-edition `NN-kilder.md` artifact (Fix #2, slice 2).
 *
 * A read-only, deterministically-rendered sources ledger: for each load-bearing
 * slot, what backs the claim. The single source of truth is the edition's
 * `livedSpecifics` slot-map + the specifics-bank — `NN-kilder.md` is regenerated
 * from them (like POST.html), never hand-edited. The coverage block and the
 * regel-6/7 number list are computed by `validateBinding`, so the artifact and
 * the skeleton-gate can never disagree.
 *
 * Pure + dateless on purpose (golden-testable). The CLI writes the string to
 * `<serie>/linkedin/NN-kilder.md`.
 */

import type { Bank, Specific } from "./types.js";
import type { LivedSpecifics, Slot } from "./binding.js";
import { validateBinding } from "./binding.js";

export interface RenderKilderInput {
  articleId: string;
  title: string;
  livedSpecifics: LivedSpecifics;
  bank: Bank;
}

function verifMarker(spec: Specific): string {
  if (spec.verification === "verified") return " · verifisert ✓";
  if (spec.verification === "unverified") return " · uverifisert ⚠";
  return ""; // n/a — no marker
}

function bindingLines(slot: Slot, byId: Map<string, Specific>): string[] {
  const b = slot.binding;
  switch (b.type) {
    case "specific": {
      const spec = byId.get(b.specificId);
      if (!spec) {
        return [`- **Binding:** ⛔ levd materiale — id \`${b.specificId}\` mangler i banken (dangling)`];
      }
      return [
        `- **Binding:** levd materiale (${spec.type}) · \`${spec.id}\`${verifMarker(spec)}`,
        `- **Materiale:** «${spec.content}»`,
        `- **Opphav:** ${spec.provenance.source}, fanget ${spec.provenance.capturedAt}`,
        `- **Tema-tagger:** ${spec.topicTags.join(", ")}`,
      ];
    }
    case "abstrakt":
      return b.rationale.trim().length === 0
        ? ["- **Binding:** ⛔ abstrakt uten begrunnelse (avvist — vaghet)"]
        : [`- **Binding:** abstrakt (med vilje) — ${b.rationale}`];
    case "ekstern":
      return [`- **Binding:** ekstern kilde — ${b.source ?? "(fylles av research, Step 2)"}`];
    case "unresolved":
      return ["- **Binding:** ⛔ uavklart — må bindes før skjelett-gaten (vaghet avvises)"];
  }
}

export function renderKilder(input: RenderKilderInput): string {
  const { articleId, title, livedSpecifics, bank } = input;
  const byId = new Map<string, Specific>(bank.specifics.map((s) => [s.id, s]));
  const { coverage, warnings } = validateBinding(livedSpecifics, bank);

  const out: string[] = [];
  out.push(`# Kilder — ${title} (${articleId})`, "");
  out.push(
    "> Auto-generert fra edition-state `livedSpecifics` + specifics-bank. Per lastbærende påstand: hva backer den.",
    "> Levd materiale er KTGs egne ord, aldri AI-oppdiktet (retning §3). Tall er uverifiserte til fakta-sjekket (regel 6/7).",
    "",
  );
  out.push("## Lastbærende påstander", "");
  if (livedSpecifics.slots.length === 0) {
    out.push("_Ingen lastbærende slots bundet ennå._", "");
  } else {
    for (const slot of livedSpecifics.slots) {
      out.push(`### ${slot.slotId} · ${slot.label}`);
      out.push(...bindingLines(slot, byId));
      out.push("");
    }
  }

  out.push("## Dekning");
  out.push(`- Lastbærende slots: ${coverage.total}`);
  out.push(`- Levd materiale: ${coverage.specific}`);
  out.push(`- Abstrakt (escape): ${coverage.abstrakt}`);
  out.push(`- Ekstern: ${coverage.ekstern}`);
  out.push(`- Uavklart (BLOCK): ${coverage.unresolved}`);
  out.push("");

  const numSlots = warnings.filter((w) => w.reason === "unverified-number").map((w) => w.slotId);
  out.push(`Tall som må verifiseres (regel 6/7): ${numSlots.length > 0 ? numSlots.join(", ") : "ingen"}`);

  return out.join("\n") + "\n";
}
