import { describe, it, expect } from "vitest";
import {
  bouwParameterCatalogus,
  beschrijfParameters,
  beschrijfParametersVoorModel,
} from "./parameter-catalogus";
import { extraheerParameters, stelModelSamen } from "./samenstellen";
import { seedModellen } from "./modellen";
import { seedOnderdelen } from "./onderdelen";
import type { ModelParameter } from "./types";

const CATALOGUS_LEEG = new Map<string, ModelParameter>();

describe("beschrijfParameters — invulhulp per parameter", () => {
  it("gebruikt de eigen declaratie (herkomst 'gedeclareerd') als die informatief is", () => {
    const eigen: ModelParameter[] = [
      { naam: "prijs_cijfers", omschrijving: "Verkoopprijs in cijfers", voorbeeld: "250.000" },
    ];
    const [hulp] = beschrijfParameters(["prijs_cijfers"], eigen, CATALOGUS_LEEG, "nl");
    expect(hulp).toEqual({
      naam: "prijs_cijfers",
      omschrijving: "Verkoopprijs in cijfers",
      voorbeeld: "250.000",
      herkomst: "gedeclareerd",
    });
  });

  it("valt terug op de bibliotheekbrede catalogus (herkomst 'catalogus')", () => {
    const catalogus = new Map<string, ModelParameter>([
      ["naam_koper", { naam: "naam_koper", omschrijving: "Volledige naam van de koper", voorbeeld: "Jan Peeters" }],
    ]);
    const [hulp] = beschrijfParameters(["naam_koper"], [], catalogus, "nl");
    expect(hulp.herkomst).toBe("catalogus");
    expect(hulp.omschrijving).toBe("Volledige naam van de koper");
    expect(hulp.voorbeeld).toBe("Jan Peeters");
  });

  it("zonder énige declaratie: verwoorde naam + waarschuwing + patroongebaseerd voorbeeld (herkomst 'afgeleid')", () => {
    const [hulp] = beschrijfParameters(["datum_bericht_klim"], [], CATALOGUS_LEEG, "nl");
    expect(hulp.herkomst).toBe("afgeleid");
    expect(hulp.omschrijving).toContain("datum bericht klim");
    expect(hulp.omschrijving).toContain("bij twijfel leeg laten");
    expect(hulp.voorbeeld).toBe("15 maart 2026"); // datum-patroon uit voorbeeldwaarden
  });

  it("vult een ontbrekend voorbeeld bij een gedeclareerde parameter aan via het naamptroon, in de juiste taal", () => {
    const eigen: ModelParameter[] = [{ naam: "date_acte", omschrijving: "Date de signature de l'acte" }];
    const [hulp] = beschrijfParameters(["date_acte"], eigen, CATALOGUS_LEEG, "fr");
    expect(hulp.herkomst).toBe("gedeclareerd");
    expect(hulp.voorbeeld).toBe("15 mars 2026");
  });

  it("een niet-informatieve eigen declaratie ([AAN TE VULLEN-placeholder) blokkeert de catalogus niet", () => {
    const eigen: ModelParameter[] = [{ naam: "gemeente", omschrijving: "[AAN TE VULLEN: gemeente]" }];
    const catalogus = new Map<string, ModelParameter>([
      ["gemeente", { naam: "gemeente", omschrijving: "Gemeente waar het goed ligt", voorbeeld: "Tervuren" }],
    ]);
    const [hulp] = beschrijfParameters(["gemeente"], eigen, catalogus, "nl");
    expect(hulp.herkomst).toBe("catalogus");
    expect(hulp.omschrijving).toBe("Gemeente waar het goed ligt");
  });
});

describe("invulhulp-garantie over de volledige bibliotheek", () => {
  // De kerninvariant achter de API/MCP-invulhulp: een agent die om het even
  // welk modeldocument invult, krijgt voor ÉLKE parameter een niet-lege
  // omschrijving en een niet-leeg voorbeeld — nooit meer een kale naam
  // waarvan de betekenis geraden moet worden.
  it("elk model geeft voor elke parameter een niet-lege omschrijving én voorbeeld", () => {
    const kaal: string[] = [];
    for (const model of seedModellen) {
      const tekst = stelModelSamen(model, seedOnderdelen);
      const hulp = beschrijfParametersVoorModel(extraheerParameters(tekst), model, seedOnderdelen);
      for (const h of hulp) {
        if (!h.omschrijving.trim() || !h.voorbeeld.trim()) kaal.push(`${model.id} :: ${h.naam}`);
      }
    }
    expect(kaal).toEqual([]);
  });

  it("de catalogus lost het merendeel van de parameters op (ratchet: aandeel 'afgeleid' mag enkel dalen)", () => {
    let totaal = 0;
    let afgeleid = 0;
    for (const model of seedModellen) {
      const tekst = stelModelSamen(model, seedOnderdelen);
      const hulp = beschrijfParametersVoorModel(extraheerParameters(tekst), model, seedOnderdelen);
      totaal += hulp.length;
      afgeleid += hulp.filter((h) => h.herkomst === "afgeleid").length;
    }
    expect(totaal).toBeGreaterThan(0);
    // Stand 2026-07-11 ná de parameterharmonisatie: 273/11319 ≈ 2,4 % (vóór de
    // harmonisatie 35 %; zie ook parameter-nergens-gedeclareerd in
    // bibliotheek-audit.test.ts). Declareer je parameters bij, dan daalt dit
    // aandeel — verlaag het plafond mee in dezelfde commit.
    expect(afgeleid / totaal).toBeLessThanOrEqual(0.05);
  });
});

describe("bouwParameterCatalogus", () => {
  it("een declaratie mét voorbeeld verdringt er één zonder", () => {
    const catalogus = bouwParameterCatalogus([
      {
        id: "a",
        titel: "A",
        categorie: "bijzonder",
        omschrijving: "t",
        tekst: "{{x}}",
        varianten: [],
        parameters: [{ naam: "x", omschrijving: "Zonder voorbeeld" }],
        toepasbaarOp: [],
        versie: "1",
        datum: "2026-01-01",
      },
      {
        id: "b",
        titel: "B",
        categorie: "bijzonder",
        omschrijving: "t",
        tekst: "{{x}}",
        varianten: [],
        parameters: [{ naam: "x", omschrijving: "Met voorbeeld", voorbeeld: "vb" }],
        toepasbaarOp: [],
        versie: "1",
        datum: "2026-01-01",
      },
    ]);
    expect(catalogus.get("x")?.voorbeeld).toBe("vb");
  });
});
