import { describe, it, expect } from "vitest";
import {
  genereerVoorbeeldwaarde,
  genereerVoorbeeldwaarden,
  vulOnderdeelVoorbeeldIn,
  vulOnderdeelVoorbeeldPlatIn,
  vulModelVoorbeeldIn,
} from "./voorbeeldwaarden";
import type { Modeldocument, Modelonderdeel } from "./types";

function maakOnderdeel(over: Partial<Modelonderdeel> & Pick<Modelonderdeel, "id">): Modelonderdeel {
  return {
    titel: over.id,
    categorie: "bijzonder",
    omschrijving: "test",
    tekst: "",
    varianten: [],
    parameters: [],
    toepasbaarOp: ["test"],
    versie: "1.0",
    datum: "2026-01-01",
    ...over,
  };
}

function maakModel(over: Partial<Modeldocument> & Pick<Modeldocument, "id" | "structuur">): Modeldocument {
  return {
    titel: over.id,
    akteType: "test",
    omschrijving: "test",
    versie: "1.0",
    datum: "2026-01-01",
    ...over,
  };
}

describe("genereerVoorbeeldwaarde", () => {
  it("gebruikt ModelParameter.voorbeeld als die aanwezig is, ongeacht taal", () => {
    const param = { naam: "iets_specifieks", omschrijving: "test", voorbeeld: "Mijn eigen voorbeeld" };
    expect(genereerVoorbeeldwaarde("iets_specifieks", "nl", param)).toBe("Mijn eigen voorbeeld");
    expect(genereerVoorbeeldwaarde("iets_specifieks", "fr", param)).toBe("Mijn eigen voorbeeld");
  });

  it("herkent een datumparameter en levert NL/FR-varianten", () => {
    expect(genereerVoorbeeldwaarde("datum_ondertekening", "nl")).toBe("15 maart 2026");
    expect(genereerVoorbeeldwaarde("datum_ondertekening", "fr")).toBe("15 mars 2026");
  });

  it("herkent een bedragparameter (kaal getal — de omringende clausuletekst schrijft de munteenheid zelf al bij)", () => {
    expect(genereerVoorbeeldwaarde("prijs_cijfers", "nl")).toBe("250.000");
  });

  it("verwart geboorteplaats niet met een geboortedatum", () => {
    expect(genereerVoorbeeldwaarde("geboorteplaats", "nl")).toBe("Leuven");
    expect(genereerVoorbeeldwaarde("geboortedatum", "nl")).toBe("12 maart 1985");
  });

  it("valt bij een onbekend patroon zonder omschrijving terug op de verwoorde parameternaam", () => {
    expect(genereerVoorbeeldwaarde("zzz_onbekend_veld", "nl")).toBe("(zzz onbekend veld)");
  });

  it("valt bij een onbekend patroon mét omschrijving terug op een korte versie daarvan", () => {
    const param = { naam: "iets_onbekends", omschrijving: "Een korte toelichting bij dit veld. Nog een zin." };
    expect(genereerVoorbeeldwaarde("iets_onbekends", "nl", param)).toBe("Een korte toelichting bij dit veld");
  });

  it("herkent een Franse datumparameter (date_...)", () => {
    expect(genereerVoorbeeldwaarde("date_permis_lotissement", "fr")).toBe("15 mars 2026");
  });

  it("herkent identiteit/plaats/numero als vaakst voorkomende Franse wortels", () => {
    // Sinds het kwaliteitsnazicht van 2026-07-10 is de comparant-identiteit de
    // VOLLEDIGE identificatie (naam, geboorte, rijksregister, woonplaats).
    expect(genereerVoorbeeldwaarde("identite_vendeurs", "fr")).toContain("DUPONT Jean");
    expect(genereerVoorbeeldwaarde("lieu_acte_anterieur", "fr")).toBe("Bruxelles");
    expect(genereerVoorbeeldwaarde("numero_cadastral_titre", "fr")).toBe("AB123456");
  });
});

describe("genereerVoorbeeldwaarden", () => {
  it("bouwt een waarde voor elke opgegeven parameternaam", () => {
    const waarden = genereerVoorbeeldwaarden(["datum_akte", "naam_koper"], [], "nl");
    expect(Object.keys(waarden).sort()).toEqual(["datum_akte", "naam_koper"]);
    expect(waarden.datum_akte).toBeTruthy();
    expect(waarden.naam_koper).toBeTruthy();
  });
});

describe("vulOnderdeelVoorbeeldIn / vulOnderdeelVoorbeeldPlatIn", () => {
  it("vult alle {{parameters}} in de basistekst en elke hypothese, zonder [AAN TE VULLEN]", () => {
    const onderdeel = maakOnderdeel({
      id: "test-onderdeel",
      tekst: "De partij {{naam_partij}} verklaart op {{datum_akte}}.",
      varianten: [{ id: "v1", hypothese: "Hypothese A", tekst: "Bedrag: {{bedrag}}." }],
    });
    const resultaat = vulOnderdeelVoorbeeldIn(onderdeel);
    expect(resultaat.basis).not.toContain("{{");
    expect(resultaat.basis).not.toContain("AAN TE VULLEN");
    expect(resultaat.varianten[0].tekst).not.toContain("{{");

    const plat = vulOnderdeelVoorbeeldPlatIn(onderdeel);
    expect(plat).toContain("HYPOTHESE — Hypothese A");
    expect(plat).not.toContain("{{");
  });

  it("gebruikt de FR-voorbeeldwaarden voor een FR-onderdeel", () => {
    const onderdeel = maakOnderdeel({
      id: "test-fr",
      taal: "fr",
      tekst: "Signé le {{datum_akte}}.",
    });
    const resultaat = vulOnderdeelVoorbeeldIn(onderdeel);
    expect(resultaat.basis).toContain("mars");
  });
});

describe("vulModelVoorbeeldIn", () => {
  it("genereert het volledige model met alle onderdelen ingevuld", () => {
    const onderdeel = maakOnderdeel({
      id: "clausule-1",
      tekst: "PRIJS\n\nDe prijs bedraagt {{bedrag}}.",
    });
    const model = maakModel({
      id: "model-1",
      structuur: [{ onderdeelId: "clausule-1", verplicht: true }],
    });
    const tekst = vulModelVoorbeeldIn(model, [onderdeel]);
    expect(tekst).not.toContain("{{");
    expect(tekst).not.toContain("AAN TE VULLEN");
  });
});

// ── Regressies uit het kwaliteitsnazicht van de notaris (2026-07-10) ─────────
// Elke case hieronder is een letterlijk gebrek uit het nagelezen
// verkoopakte-heldere-taal-voorbeeld: een parameter die op het verkeerde
// patroon viel en de akte onleesbaar of rekenkundig onmogelijk maakte.
describe("genereerVoorbeeldwaarde — kwaliteitsnazicht verkoopakte (regressies)", () => {
  const nl = (naam: string) => genereerVoorbeeldwaarde(naam, "nl");

  it("kadastraal_inkomen met underscore matcht (geen omschrijving-fallback met dubbele euro)", () => {
    expect(nl("kadastraal_inkomen_goed")).toBe("1.250");
    expect(nl("niet_geindexeerd_kadastraal_inkomen")).toBe("1.250");
  });

  it("bedragen zijn gedifferentieerd en voluit spoort met cijfers", () => {
    expect(nl("voorschot_cijfers")).toBe("25.000");
    expect(nl("voorschot_letters")).toBe("vijfentwintigduizend");
    expect(nl("saldo_cijfers")).toBe("225.000");
    expect(nl("saldo_letters")).toBe("tweehonderdvijfentwintigduizend");
    expect(nl("prijs_voluit")).toBe("tweehonderdvijftigduizend");
    expect(nl("rente_letters")).toBe("duizend honderdvijftig");
    // maandelijkse vergoeding is geen 250.000
    expect(nl("maandelijkse_vergoeding_bewoning")).toBe("950");
    expect(nl("bedrag_huurwaarborg")).toBe("1.900");
  });

  it("aandeel onroerende voorheffing is een EUR-bedrag, geen breuk", () => {
    expect(nl("aandeel_onroerende_voorheffing")).toBe("185,50");
  });

  it("EPC/PEB-verbruik, -geldigheid en -deskundige zijn geen certificaatnummer", () => {
    expect(nl("verbruik_epc")).toBe("245");
    expect(nl("consommation_peb")).toBe("245");
    expect(nl("geldigheid_peb")).toBe("15 maart 2036");
    expect(nl("epc_energiedeskundige")).toBe("Els Vermeulen");
  });

  it("verdieping-beschrijving en -nummer vallen niet op de nummer-match", () => {
    expect(nl("beschrijving_eerste_verdieping")).toBe("hal, woonkamer, open keuken en badkamer");
    expect(nl("nummer_verdieping")).toBe("2e");
  });

  it("een lot op het plan is geen vennootschapsnaam", () => {
    expect(nl("benaming_lot_op_plan")).toBe("3");
  });

  it("het antwoord van gemeente/ambtenaar is inhoud, geen plaatsnaam", () => {
    expect(nl("antwoord_gemeente")).toBe("gunstig, zonder opmerkingen");
    expect(nl("antwoord_ambtenaar")).toBe("gunstig, zonder opmerkingen");
  });

  it("verkoper en koper dragen verschillende demo-namen (geen verkoop aan zichzelf)", () => {
    expect(nl("identiteit_verkopers")).not.toBe(nl("identiteit_kopers"));
    expect(nl("naam_verkoper")).toBe("Jan Peeters");
    expect(nl("naam_koper")).toBe("Marie Janssens");
    // de instemmende echtgenoot is geen van beide partijen
    expect(nl("identiteit_echtgenoot")).toBe("Sofie De Smet");
  });

  it("de oorsprong van eigendom is een volwaardige alinea, geen kale omschrijving", () => {
    expect(nl("oorsprong_van_eigendom")).toContain("verkreeg het goed bij akte");
  });

  it("lasten per trimester zijn een klein bedrag, geen omschrijving-fallback", () => {
    expect(nl("lasten_per_trimester")).toBe("450");
  });
});

// ── Regressies uit het tweede kwaliteitsnazicht (FR-verkoopakte, 2026-07-10) ─
describe("genereerVoorbeeldwaarde — kwaliteitsnazicht 2 (FR-akte)", () => {
  const nl = (naam: string) => genereerVoorbeeldwaarde(naam, "nl");
  const fr = (naam: string) => genereerVoorbeeldwaarde(naam, "fr");

  it("de identiteit van verkoper/koper is de VOLLEDIGE identificatie, geen kale naam", () => {
    // Sinds nazicht 3 (2026-07-11) gegenereerd uit de canonieke clausule
    // "identiteit-partijen": "ingeschreven in het rijksregister onder nummer".
    expect(nl("identiteit_verkopers")).toContain("rijksregister");
    expect(nl("identiteit_verkopers")).toContain("geboren te");
    expect(fr("identite_vendeurs")).toContain("registre national");
    expect(fr("identite_acquereurs")).toContain("domiciliée");
    // de korte naam-parameters blijven kort
    expect(nl("naam_verkoper")).toBe("Jan Peeters");
  });

  it("nazicht 3: de identiteit hergebruikt de canonieke clausule mét huwelijksalinea", () => {
    expect(nl("identiteit_verkopers")).toContain("onder het stelsel van scheiding van goederen");
    expect(nl("identiteit_verkopers")).toContain("welk stelsel tot op heden niet werd gewijzigd");
    expect(nl("identiteit_verkopers")).toContain("zoals hij verklaart");
    expect(fr("identite_vendeurs")).toContain("sous le régime de la séparation de biens");
    // de tussenkomende partner is een volledige inline-identiteit, en niet de
    // verkoper zelf
    expect(nl("identiteit_partner_verkoper")).toContain("DE SMET Sofie");
    expect(nl("identiteit_partner_verkoper")).not.toContain("PEETERS");
    expect(fr("identite_partenaire")).toContain("LAMBERT Sophie");
  });

  it("nazicht 3: tweede/tussenkomende notaris draagt een andere naam en standplaats", () => {
    expect(nl("naam_tussenkomende_notaris")).toBe("Peter Van Hove");
    expect(nl("naam_tussenkomende_notaris")).not.toBe(nl("naam_notaris"));
    expect(nl("standplaats_tussenkomende_notaris")).not.toBe(nl("standplaats"));
    expect(nl("naam_notaris")).toBe("Ann Janssens");
  });

  it("nazicht 3: de aktedatum voluit herhaalt het jaartal niet", () => {
    expect(nl("datum_akte_voluit")).toBe("vijftien maart");
    expect(fr("datum_akte_voluit")).toBe("quinze mars");
  });

  it("nazicht 3: de kostenverdeling van een tank is een afspraak, geen literinhoud", () => {
    expect(nl("kostenverdeling_tank")).toContain("de helft van de kosten");
    expect(fr("kostenverdeling_tank")).toContain("la moitié des frais");
    expect(nl("inhoud_stookolietank")).toBe("1.500");
  });

  it("nazicht 3: één wooneenheid, sporend met de demo-bestemming", () => {
    expect(nl("aantal_wooneenheden")).toBe("1");
  });

  it("nature_du_lot en description_lot_privatif vallen NIET op de lot-match (regressie nazicht 1)", () => {
    expect(fr("nature_du_lot")).toBe("appartement");
    expect(fr("description_lot_privatif")).not.toBe("3");
  });

  it("quote-part in de gemene delen is een breuk, geen plaatsnaam", () => {
    expect(fr("quote_part_parties_communes")).toBe("3/1.000e");
    expect(fr("quote_part_parties_communes_generales")).toBe("3/1.000e");
  });

  it("het kantoor Rechtszekerheid is een kantooraanduiding, geen kale gemeente", () => {
    expect(fr("bureau_securite_juridique_numero_et_commune")).toContain("Sécurité juridique");
    expect(nl("kantoor_rechtszekerheid_met_nummer_en_gemeente")).toContain("Rechtszekerheid");
  });

  it("de inhoud van een gemeentebrief is inhoud, geen plaatsnaam", () => {
    expect(fr("contenu_lettre_commune")).toBe("favorable, sans remarques");
  });

  it("FR-verdiepingsnummers met rangtelwoord vallen niet op de nummer-match", () => {
    expect(fr("numero_premier_etage")).toBe("2");
    expect(fr("numero_deuxieme_etage")).toBe("2");
  });

  it("KI/RC voluit spoort in woorden met het cijfer", () => {
    expect(nl("ki_samen_woorden")).toBe("duizend tweehonderdvijftig");
    expect(nl("ki_appartement_woorden")).toBe("duizend tweehonderdvijftig");
  });

  it("de ligging in het gebouw is een plaatsbeschrijving", () => {
    expect(fr("emplacement_dans_immeuble")).toBe("à gauche du hall d'entrée");
  });
});
