import { describe, it, expect } from "vitest";
// ── A-tot-Z testloop voor het Einddoel ───────────────────────────────────────
// Doorloopt het volledige proces zoals in productie: bron-extractie-JSON (v2,
// met conflict) → dossier → bijkomende bron samenvoegen → conflict valideren →
// volledig werkdossier (ontwerp + modelmails + afrekening). Bewaakt dat de drie
// pijlers samen een bruikbaar werkdocument opleveren met de gekende gegevens
// ingevuld en de onzekerheden eerlijk gemeld.
import { dossierVeldenUitIntake, voegIntakeVeldenSamen, voegAttestenSamen, maakDossierUitIntakeResultaat, DOSSIER_INTAKE_SCHEMA } from "./intake";
import { berekenTegenstrijdigheden, kiesPrimaireBron } from "./tegenstrijdigheden";
import { stelWerkdossierSamenAutonoom } from "./werkdossier";
import { kenmerkenNaarKeuzes } from "./kenmerken";
import { type Dossier } from "./types";
import { seedModellen, seedOnderdelen, genereerDocument, pasKeuzesToe } from "@/data/modeldocumenten";
import { seedBrieven } from "@/data/modelbrieven";

const COMPROMIS_JSON = {
  schema: DOSSIER_INTAKE_SCHEMA,
  dossiertype: "verkoop-zonder-krediet",
  verkoopdocument: "verkoopakte",
  referentie: "2026/0456",
  bron: "compromis",
  brondocumentId: "compromis.pdf",
  partijen: [
    { naam: "PEETERS", voornaam: "Jan", rol: "verkoper", geslacht: "man", burgerlijkeStaat: "ongehuwd", geboortedatum: "1965-02-20", geboorteplaats: "Mechelen", rijksregisternummer: "65022012345", adres: "Kerkstraat 8, 3080 Tervuren" },
    { naam: "MAES", voornaam: "Sofie", rol: "koper", geslacht: "vrouw", burgerlijkeStaat: "ongehuwd" },
  ],
  goed: { adres: "Bosstraat 45, 3080 Tervuren", type: "woning", gemeente: "Tervuren", sectie: "C", perceelnummer: "88/B", kadastraalInkomen: 1320, oppervlakte: 540 },
  prijs: 395000,
  voorschot: 39500,
  compromisdatum: "2026-05-12",
  attesten: {
    epc: { datum: "2026-01-15", nummer: "EPC-987", label: "D", geldigTot: "2036-01-15" },
    bodem: { datum: "2026-05-02", inhoud: "blanco" },
    elektrischeKeuring: { organisme: "Vinçotte", datum: "2026-05-10", conclusie: "conform" },
  },
};

// Bijkomende bron (eigendomstitel) met een afwijkende prijs → tegenstrijdigheid.
const TITEL_JSON = {
  schema: DOSSIER_INTAKE_SCHEMA,
  bron: "eigendomstitel",
  brondocumentId: "titel.pdf",
  prijs: 400000,
};

describe("Einddoel A-tot-Z testloop (verkoopakte)", () => {
  function bouwDossier(): Dossier {
    return maakDossierUitIntakeResultaat(dossierVeldenUitIntake(COMPROMIS_JSON), {
      id: "loop-1",
      status: "ontwerp-in-opmaak",
      aangemaakt: "2026-06-01T00:00:00.000Z",
      aangepast: "2026-06-01T00:00:00.000Z",
      standaardDossiertype: "verkoop-zonder-krediet",
    });
  }

  it("A. bron-extractie levert een volledig, foutloos dossier op", () => {
    const r = dossierVeldenUitIntake(COMPROMIS_JSON);
    expect(r.problemen).toEqual([]);
    expect(r.dossiertype).toBe("verkoop-zonder-krediet");
    expect(r.verkoopdocument).toBe("verkoopakte");
    expect(r.referentie).toBe("2026/0456");
    expect(r.velden.partijen?.waarde).toHaveLength(2);
    expect(r.attesten?.epc?.nummer).toBe("EPC-987");
  });

  it("B. bijkomende bron samenvoegen levert een gemarkeerde tegenstrijdigheid", () => {
    let dossier = bouwDossier();
    const extra = dossierVeldenUitIntake(TITEL_JSON);
    dossier = voegIntakeVeldenSamen(dossier, extra.velden);
    const samen = voegAttestenSamen(dossier.attesten, extra.attesten);
    if (samen) dossier.attesten = samen;
    dossier.tegenstrijdigheden = berekenTegenstrijdigheden(dossier);

    const prijsConflict = dossier.tegenstrijdigheden.find((t) => t.veldSleutel === "prijs");
    expect(prijsConflict).toBeDefined();
    // Eigendomstitel (hoger gezag) is primair geworden.
    expect(dossier.prijs?.waarde).toBe(400000);
    expect(dossier.prijs?.bron).toBe("eigendomstitel");
  });

  it("C. conflict valideren: notaris kiest het compromis als juiste bron", () => {
    let dossier = bouwDossier();
    const extra = dossierVeldenUitIntake(TITEL_JSON);
    dossier = voegIntakeVeldenSamen(dossier, extra.velden);
    // Notaris duidt het compromis aan als de juiste prijs.
    dossier.prijs = kiesPrimaireBron(dossier.prijs!, "compromis");
    expect(dossier.prijs?.waarde).toBe(395000);
    expect(dossier.prijs?.bron).toBe("compromis");
  });

  it("D. volledig werkdossier: ontwerp + modelmails + afrekening kloppen", () => {
    const wd = stelWerkdossierSamenAutonoom(
      bouwDossier(),
      { modellen: seedModellen, onderdelen: seedOnderdelen, brieven: seedBrieven },
      "Vlaanderen"
    );

    // Pijler 1 — ontwerp: juist model, gekende gegevens ingevuld.
    expect(wd.ontwerpakte.akteTypeKeuze.akteType).toBe("verkoopakte");
    expect(wd.ontwerpakte.akteTypeKeuze.zekerheid).toBe("zeker");
    const tekst = wd.ontwerpakte.tekst ?? "";
    // Canonieke clausule "identiteit-partijen": NAAM (hoofdletters) + voornamen.
    expect(tekst).toContain("De heer PEETERS Jan");
    expect(tekst).toContain("20 februari 1965"); // datum voluit
    expect(tekst).toContain("Tervuren"); // standplaats uit kantoorinstellingen
    expect(tekst).not.toContain("[AAN TE VULLEN: aanspreking]"); // aanspreking opgelost (keuzevorm bij onbekend geslacht is toegelaten)
    expect(tekst).not.toContain("[AAN TE VULLEN: standplaats]");
    expect(tekst).not.toContain("[AAN TE VULLEN: naam_notaris]");

    // Pijler 2 — modelmails: relevant en met ingevulde referte/aanhef.
    expect(wd.modelmails.mails.length).toBeGreaterThan(0);
    const koperMail = wd.modelmails.mails.find((m) => /koper \(cli/i.test(m.brief.ontvanger));
    expect(koperMail?.ingevuld.tekst).toContain("Sofie MAES");

    // Pijler 3 — afrekening: ereloon + verkooprecht (afgerond).
    expect(wd.afrekening.aktekosten?.totaal).toBeGreaterThan(0);
    expect(wd.afrekening.registratiebelasting?.bedrag).toBe(47400); // 12% van 395.000
    expect(Number.isInteger(wd.afrekening.registratiebelasting?.bedrag)).toBe(true);

    // Onzekerheden zijn aanwezig (eerlijk) maar geen kerngegeven ontbreekt.
    expect(wd.onzekerheden.length).toBeGreaterThan(0);
  });

  it("F. schenking gouden pad: schenkingsakte + schenkbelasting + relevante mails", () => {
    const r = dossierVeldenUitIntake({
      schema: DOSSIER_INTAKE_SCHEMA,
      dossiertype: "schenking",
      referentie: "2026/0789",
      bron: "verklaring-partij",
      partijen: [
        { naam: "PEETERS", voornaam: "Jan", rol: "schenker", geslacht: "man" },
        { naam: "PEETERS", voornaam: "Lotte", rol: "begiftigde", geslacht: "vrouw" },
      ],
      goed: { adres: "Bosstraat 45, 3080 Tervuren", type: "woning" },
      belastbareWaarde: 250000,
      relatieBelasting: "rechte_lijn_partner",
      goedTypeBelasting: "onroerend",
    });
    const dossier: Dossier = maakDossierUitIntakeResultaat(r, {
      id: "loop-schenk",
      status: "ontwerp-in-opmaak",
      aangemaakt: "2026-06-01T00:00:00.000Z",
      aangepast: "2026-06-01T00:00:00.000Z",
      standaardDossiertype: "schenking",
    });

    const wd = stelWerkdossierSamenAutonoom(
      dossier,
      { modellen: seedModellen, onderdelen: seedOnderdelen, brieven: seedBrieven },
      "Vlaanderen"
    );
    expect(wd.ontwerpakte.akteTypeKeuze.akteType).toBe("schenkingsakte");
    expect(wd.ontwerpakte.model?.id).toBe("schenkingsakte-onroerend");
    expect(wd.afrekening.belasting?.soort).toBe("schenking");
    expect(wd.afrekening.belasting?.resultaat.totaal).toBeGreaterThan(0);
    expect(wd.modelmails.categorieen).toContain("schenking");
  });

  it("E. MCP-pad: kenmerken passen het ontwerp deterministisch aan (appartement vs woning)", () => {
    const model = seedModellen.find((m) => m.id === "verkoopovereenkomst-compromis")!;
    const genereer = (goedType: "woning" | "appartement") => {
      const keuzes = pasKeuzesToe(model, kenmerkenNaarKeuzes({ gewest: "Vlaanderen", goedType }));
      return genereerDocument(model, seedOnderdelen, keuzes, {}, []);
    };
    const woning = genereer("woning");
    const appartement = genereer("appartement");
    // Dezelfde feiten leiden reproduceerbaar tot een ander, passend ontwerp.
    expect(woning).not.toBe(appartement);
    expect(appartement.toLowerCase()).toContain("mede-eigendom");
    // En het is deterministisch: tweemaal hetzelfde resultaat.
    expect(genereer("appartement")).toBe(appartement);
  });
});
