import { describe, it, expect } from "vitest";
// ── Gouden-paden-register: één ratchet-test voor álle gouden paden ────────────
// Elk scenario in GOUDEN_PADEN wordt hier end-to-end door de volledige motor
// gehaald (detectie → model → invulling → mails → afrekening) en bewaakt met
// ratchet-plafonds. Een nieuw gouden pad bewaken = één scenario toevoegen aan
// `gouden-paden.ts` — dit bestand hoeft nooit te veranderen.
//
// Faalt een scenario, dan is dat pad geregresseerd (of verbeterd: verlaag dan
// het plafond / zet de pijler-vlag om — bewust, nooit stilzwijgend).
import { beoordeelGoudenPad, bouwScenarioDossier } from "./gouden-pad";
import { GOUDEN_PADEN } from "./gouden-paden";
import { seedModellen, seedOnderdelen } from "@/data/modeldocumenten";
import { seedBrieven } from "@/data/modelbrieven";

const BIBLIOTHEKEN = { modellen: seedModellen, onderdelen: seedOnderdelen, brieven: seedBrieven };

describe("Gouden-paden-register", () => {
  it("het register is gezond: unieke namen, plafonds enkel op gemeten paden", () => {
    const namen = GOUDEN_PADEN.map((s) => s.naam);
    expect(new Set(namen).size).toBe(namen.length);
    for (const s of GOUDEN_PADEN) {
      // Een FR-spiegel meegeven zonder FR-plafonds (of omgekeerd) is een
      // half-geconfigureerd scenario — dat mag nooit stil passeren.
      expect(
        s.frModelId !== undefined,
        `${s.naam}: frModelId en maxOpenVeldenFr/maxOpenKeuzesFr horen samen`
      ).toBe(s.maxOpenVeldenFr !== undefined && s.maxOpenKeuzesFr !== undefined);
    }
  });

  describe.each(GOUDEN_PADEN.map((s) => [s.naam, s] as const))("%s", (_naam, scenario) => {
    const meting = beoordeelGoudenPad(scenario, BIBLIOTHEKEN);

    it("het intake-JSON passeert de éne dossier-bouwer zonder verlies van het dossiertype", () => {
      const dossier = bouwScenarioDossier(scenario);
      expect(dossier.dossiertype).toBe(scenario.intake.dossiertype);
    });

    it("de detectie kiest deterministisch het verwachte akteType en model", () => {
      expect(meting.akteType).toBe(scenario.verwachtAkteType);
      expect(meting.zekerheid).toBe("zeker");
      expect(meting.nl.modelId).toBe(scenario.verwachtModelId);
    });

    it("blijft op of onder de NL-ratchet-plafonds (open velden + open hypothesekeuzes)", () => {
      expect(
        meting.nl.openVelden.length,
        `open velden: ${meting.nl.openVelden.join(", ")}`
      ).toBeLessThanOrEqual(scenario.maxOpenVelden);
      expect(meting.nl.openKeuzes).toBeLessThanOrEqual(scenario.maxOpenKeuzes);
    });

    it("de FR-spiegel volgt dezelfde ratchet (of is een gekend gat op de werklijst)", () => {
      if (!scenario.frModelId) {
        expect(meting.fr).toBeUndefined();
        return;
      }
      expect(meting.fr!.modelId).toBe(scenario.frModelId);
      expect(
        meting.fr!.openVelden.length,
        `open velden (FR): ${meting.fr!.openVelden.join(", ")}`
      ).toBeLessThanOrEqual(scenario.maxOpenVeldenFr!);
      expect(meting.fr!.openKeuzes).toBeLessThanOrEqual(scenario.maxOpenKeuzesFr!);
    });

    // De mail- en afrekeningpijler zijn gemeten gedrag (meting.heeftMails/
    // heeftAfrekening, backlogpunt 19); hun bewuste omslag bewaakt de
    // volwassenheids-ratchet in gouden-pad-volwassenheid.test.ts.
  });
});
