import { describe, it, expect } from "vitest";
import { voegAuditRegelToe, verifieerAuditKetting, berekenAuditHash, type AuditGebeurtenis, type AuditRegel } from "./audit";
import { beslisEscalatie, bepaalZekerheid, veiligeStandaardregel } from "./autonomie";

// ── AUT-O2 · Verantwoordings-/audit-model ────────────────────────────────────
// Bewaakt de append-only hashketen en de integriteitscontrole; de audit sluit
// rechtstreeks aan op de AUT-O1-besluiten.

function gebeurtenis(over: Partial<AuditGebeurtenis> = {}): AuditGebeurtenis {
  const besluit = beslisEscalatie(veiligeStandaardregel("opzoeking-hypothecaire-staat", "midden"), bepaalZekerheid([{ omschrijving: "alles ok", positief: true }]));
  return {
    dossierRef: "dossier-2026-0456", // pseudoniem, geen persoonsgegevens
    handelingstype: "opzoeking-hypothecaire-staat",
    tier: "handelen-extern",
    besluit,
    gronden: [{ omschrijving: "alle feiten aanwezig", positief: true }],
    uitvoerder: "notaris",
    tijdstip: "2026-07-05T09:40:00.000Z",
    ...over,
  };
}

describe("voegAuditRegelToe — append-only ketting", () => {
  it("nummert door, koppelt vorigeHash en laat bestaande regels ongemoeid", () => {
    const k1 = voegAuditRegelToe([], gebeurtenis());
    const k2 = voegAuditRegelToe(k1, gebeurtenis({ handelingstype: "mail-versturen", tijdstip: "2026-07-05T10:00:00.000Z" }));
    expect(k1.length).toBe(1);
    expect(k2.length).toBe(2);
    expect(k2[0]).toEqual(k1[0]); // append-only: eerste regel onveranderd
    expect(k2[0].volgnummer).toBe(1);
    expect(k2[1].volgnummer).toBe(2);
    expect(k2[1].vorigeHash).toBe(k2[0].hash);
    expect(k2[0].vorigeHash).toBe("");
  });

  it("neemt het AUT-O1-besluit (beslissing + niveau + reden) in de regel op", () => {
    const [regel] = voegAuditRegelToe([], gebeurtenis());
    expect(regel.besluit.beslissing).toBe("escaleren"); // default-deny tier 3
    expect(regel.besluit.zekerheidsniveau).toBe("zeker");
  });
});

describe("verifieerAuditKetting — integriteit", () => {
  const ketting = [gebeurtenis(), gebeurtenis({ handelingstype: "mail-versturen" }), gebeurtenis({ handelingstype: "neerlegging" })]
    .reduce<AuditRegel[]>((k, g) => voegAuditRegelToe(k, g), []);

  it("aanvaardt een ongewijzigde ketting", () => {
    expect(verifieerAuditKetting(ketting)).toEqual({ geldig: true });
  });

  it("detecteert een gewijzigde regel (inhoud komt niet overeen met de hash)", () => {
    const geknoeid = ketting.map((r, i) => (i === 1 ? { ...r, handelingstype: "iets-anders" } : r));
    const controle = verifieerAuditKetting(geknoeid);
    expect(controle.geldig).toBe(false);
    expect(controle.brekingBij).toBe(2);
  });

  it("detecteert een verwijderde regel (gebroken volgnummer/koppeling)", () => {
    const zonderTweede = [ketting[0], ketting[2]];
    const controle = verifieerAuditKetting(zonderTweede);
    expect(controle.geldig).toBe(false);
    expect(controle.brekingBij).toBe(2);
  });

  it("detecteert een omgewisselde volgorde", () => {
    const omgewisseld = [ketting[1], ketting[0], ketting[2]];
    expect(verifieerAuditKetting(omgewisseld).geldig).toBe(false);
  });

  it("een lege ketting is geldig", () => {
    expect(verifieerAuditKetting([])).toEqual({ geldig: true });
  });
});

describe("berekenAuditHash — deterministisch en inhoudsgevoelig", () => {
  it("zelfde inhoud → zelfde hash; gewijzigd tijdstip → andere hash", () => {
    const basis = { ...gebeurtenis(), volgnummer: 1, vorigeHash: "" };
    expect(berekenAuditHash(basis)).toBe(berekenAuditHash({ ...basis }));
    expect(berekenAuditHash(basis)).not.toBe(berekenAuditHash({ ...basis, tijdstip: "2026-07-05T11:11:11.000Z" }));
  });
});
