import { describe, expect, it } from "vitest";
import { seedModellen, seedOnderdelen } from "./index";
import type { Modeldocument, Modelonderdeel } from "./types";

// ── Vormvereisten van de authentieke akte (instructie notaris, 2026-07-05) ───
// Elke akte moet BEGINNEN met de datum en de instrumenterende notaris (de
// aanhef) en EINDIGEN met de plaats van het verlijden, de toelichting/
// voorlezing en de ondertekening (de slotformule) — vermeldingen op straffe
// van nietigheid (art. 12 Organieke Wet Notarisambt). Deze test dwingt dat af
// voor ÉLK model met `authentiekeAkte: true`, NL én FR: een nieuw aktemodel
// zonder aanhef of zonder volwaardige slotformule wordt hier rood.

const onderdeelById = new Map(seedOnderdelen.map((o) => [o.id, o]));

/** De erkende aanhef-onderdelen (datum + notaris, art. 12 OWN). */
const AANHEF_IDS = new Set(["aanhef-akte", "aanhef-akte-fr"]);

/**
 * Uitzonderingen, elk met een juridische motivering — deze lijst mag enkel
 * krimpen, nooit stilzwijgend groeien:
 * - eigenhandig testament (art. 970 oud BW): geheel geschreven, gedagtekend en
 *   ondertekend door de hand van de erflater zélf — de notariële aanhef en
 *   slotformule (voorlezing door de notaris) gelden daar per definitie niet.
 */
const UITZONDERINGEN = new Set([
  "keuzetestament",
  "keuzetestament-fr",
  "testament-gezinswoning-partner-restlegaat-kinderen",
  "testament-gezinswoning-partner-restlegaat-kinderen-fr",
]);

/** Alle tekst van een onderdeel (basistekst + alle varianten). */
function volledigeTekst(onderdeel: Modelonderdeel): string {
  return [onderdeel.tekst, ...onderdeel.varianten.map((v) => v.tekst)].join("\n");
}

const PLAATS = /verleden te|passé à|reçu à|\{\{standplaats\}\}|\{\{plaats_verlijden\}\}/i;
const VOORLEZING = /voorlezing|voorgelezen|lezing|toelichting|toegelicht|commentaar|lecture|commenté/i;
const ONDERTEKENING = /teken|onderteken|getekend|sign/i;
const DATUM = /\{\{datum_akte_voluit\}\}|het jaar|l'an/i;
const NOTARIS = /notaris|notaire/i;

const akteModellen: Modeldocument[] = seedModellen.filter(
  (m) => m.authentiekeAkte && !UITZONDERINGEN.has(m.id)
);

describe("vormvereisten authentieke akte (art. 12 OWN — op straffe van nietigheid)", () => {
  it("er zijn authentieke aktemodellen om te bewaken (de meetlat is niet leeg)", () => {
    expect(akteModellen.length).toBeGreaterThan(40);
  });

  it("de aanhef zelf draagt datum én notaris, in beide talen", () => {
    for (const id of AANHEF_IDS) {
      const aanhef = onderdeelById.get(id);
      expect(aanhef, `aanhef-onderdeel "${id}" ontbreekt in de bibliotheek`).toBeDefined();
      const tekst = volledigeTekst(aanhef!);
      expect(tekst, `${id}: datum ontbreekt`).toMatch(DATUM);
      expect(tekst, `${id}: notaris ontbreekt`).toMatch(NOTARIS);
    }
  });

  it("elke akte BEGINT met de aanhef (datum en notaris), uiterlijk als tweede onderdeel (na het interne informatieblok)", () => {
    for (const model of akteModellen) {
      const eerste = model.structuur.slice(0, 2).map((s) => s.onderdeelId);
      expect(
        eerste.some((id) => AANHEF_IDS.has(id)),
        `${model.id}: geen aanhef-akte binnen de eerste twee onderdelen (gevonden: ${eerste.join(", ")})`
      ).toBe(true);
      const aanhefItem = model.structuur.find((s) => AANHEF_IDS.has(s.onderdeelId));
      expect(aanhefItem?.verplicht, `${model.id}: de aanhef moet verplicht zijn`).toBe(true);
    }
  });

  it("elke akte EINDIGT met plaats, toelichting/voorlezing en ondertekening (de slotformule)", () => {
    for (const model of akteModellen) {
      const laatsteId = model.structuur[model.structuur.length - 1]?.onderdeelId;
      const laatste = laatsteId ? onderdeelById.get(laatsteId) : undefined;
      expect(laatste, `${model.id}: laatste onderdeel "${laatsteId}" niet gevonden`).toBeDefined();
      const tekst = volledigeTekst(laatste!);
      expect(tekst, `${model.id}: slot "${laatsteId}" mist de PLAATS van het verlijden`).toMatch(PLAATS);
      expect(tekst, `${model.id}: slot "${laatsteId}" mist de TOELICHTING/VOORLEZING`).toMatch(VOORLEZING);
      expect(tekst, `${model.id}: slot "${laatsteId}" mist de ONDERTEKENING`).toMatch(ONDERTEKENING);
    }
  });

  it("de uitzonderingslijst bevat enkel de eigenhandig-testamentmodellen (mag enkel krimpen)", () => {
    // Elke uitzondering moet blijven bestaan als model; een nieuw aktemodel kan
    // dus nooit stilzwijgend aan de vormvereisten ontsnappen door hier te belanden.
    const modelIds = new Set(seedModellen.map((m) => m.id));
    for (const id of UITZONDERINGEN) {
      expect(modelIds.has(id), `uitzondering "${id}" bestaat niet (meer) als model — schrap ze uit de lijst`).toBe(true);
    }
    expect(UITZONDERINGEN.size).toBeLessThanOrEqual(4);
  });
});
