import { describe, test } from "node:test";
import assert from "node:assert/strict";

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

function mkSpecific(over: Partial<Specific> & { id: string }): Specific {
  return {
    id: over.id,
    type: over.type ?? "other",
    content: over.content ?? "x",
    topicTags: over.topicTags ?? ["t"],
    provenance: over.provenance ?? { capturedAt: "2026-06-20", source: "test" },
    verification: over.verification ?? "n/a",
    status: over.status ?? "active",
  };
}

const mkBank = (specifics: Specific[]): Bank => ({ schemaVersion: 1, specifics });
const ls = (slots: Slot[]): LivedSpecifics => ({ slots, status: "pending" });

describe("renderKilder — the NN-kilder.md artifact", () => {
  test("golden render of a mixed edition (specific-number-unverified + abstrakt + ekstern + unresolved)", () => {
    const bank = mkBank([
      mkSpecific({
        id: "num1",
        type: "number",
        verification: "unverified",
        content: "Sparte to dager i uka.",
        topicTags: ["saksbehandling", "tid"],
        provenance: { capturedAt: "2026-06-19", source: "seres/05" },
      }),
    ]);
    const livedSpecifics = ls([
      {
        slotId: "kp1",
        kind: "key-point",
        label: "Saksbehandling ble raskere",
        binding: { type: "specific", specificId: "num1" },
      },
      {
        slotId: "kp2",
        kind: "key-point",
        label: "Verktøyet bærer faget",
        binding: { type: "abstrakt", rationale: "Poenget er prinsippet, ikke et enkelttilfelle." },
      },
      {
        slotId: "kp3",
        kind: "key-point",
        label: "LinkedIn ranker på relevans",
        binding: { type: "ekstern" },
      },
      {
        slotId: "kp4",
        kind: "key-point",
        label: "Noe uavklart",
        binding: { type: "unresolved" },
      },
    ]);

    const expected = `# Kilder — Maskinrommet (05)

> 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).

## Lastbærende påstander

### kp1 · Saksbehandling ble raskere
- **Binding:** levd materiale (number) · \`num1\` · uverifisert ⚠
- **Materiale:** «Sparte to dager i uka.»
- **Opphav:** seres/05, fanget 2026-06-19
- **Tema-tagger:** saksbehandling, tid

### kp2 · Verktøyet bærer faget
- **Binding:** abstrakt (med vilje) — Poenget er prinsippet, ikke et enkelttilfelle.

### kp3 · LinkedIn ranker på relevans
- **Binding:** ekstern kilde — (fylles av research, Step 2)

### kp4 · Noe uavklart
- **Binding:** ⛔ uavklart — må bindes før skjelett-gaten (vaghet avvises)

## Dekning
- Lastbærende slots: 4
- Levd materiale: 1
- Abstrakt (escape): 1
- Ekstern: 1
- Uavklart (BLOCK): 1

Tall som må verifiseres (regel 6/7): kp1
`;

    assert.equal(renderKilder({ articleId: "05", title: "Maskinrommet", livedSpecifics, bank }), expected);
  });

  test("a verified named-case renders ✓ and no number-verification line", () => {
    const bank = mkBank([
      mkSpecific({ id: "c1", type: "named-case", verification: "verified", content: "Etat X." }),
    ]);
    const out = renderKilder({
      articleId: "01",
      title: "T",
      livedSpecifics: ls([
        { slotId: "kp1", kind: "key-point", label: "L", binding: { type: "specific", specificId: "c1" } },
      ]),
      bank,
    });
    assert.match(out, /levd materiale \(named-case\) · `c1` · verifisert ✓/);
    assert.match(out, /Tall som må verifiseres \(regel 6\/7\): ingen/);
  });

  test("a dangling specific id renders an explicit dangling note", () => {
    const out = renderKilder({
      articleId: "01",
      title: "T",
      livedSpecifics: ls([
        { slotId: "kp1", kind: "key-point", label: "L", binding: { type: "specific", specificId: "ghost" } },
      ]),
      bank: mkBank([]),
    });
    assert.match(out, /⛔ levd materiale — id `ghost` mangler i banken \(dangling\)/);
  });

  test("an empty slot-map renders the 'ingen slots' placeholder, not an empty section", () => {
    const out = renderKilder({ articleId: "01", title: "T", livedSpecifics: ls([]), bank: mkBank([]) });
    assert.match(out, /_Ingen lastbærende slots bundet ennå\._/);
    assert.match(out, /- Lastbærende slots: 0/);
  });
});
