import { describe, it, expect } from "vitest";
import JSZip from "jszip";
import { seedModellen, seedOnderdelen, genereerDocument, standaardKeuzes } from "@/data/modeldocumenten";
import { genereerAkteUitSjabloon } from "./akteSjabloon";

async function akteDocx(modelId: string, taal: "nl" | "fr") {
  const m = seedModellen.find((x) => x.id === modelId)!;
  const ontwerp = genereerDocument(m, seedOnderdelen, standaardKeuzes(m), {}, []);
  const eersteOnderdeelId = m.structuur[0]?.onderdeelId;
  const slaHoofdingOver = eersteOnderdeelId === "hoofding-akte" || eersteOnderdeelId === "hoofding-akte-fr";
  const buf = await genereerAkteUitSjabloon(ontwerp, { taal, slaHoofdingOver });
  expect(buf).not.toBeNull();
  return JSZip.loadAsync(buf!);
}

describe("akte template-merge: kantoorlay-out overgenomen (NL)", () => {
  it("levert een geldig .docx met welgevormde document.xml", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const xml = await zip.file("word/document.xml")!.async("string");
    expect(xml).toContain("<w:body>");
    expect(xml).toContain("</w:body>");
  });

  it("behoudt de benoemde stijlen en de sectPr (paginaopmaak/hoofding-koppeling) van het sjabloon", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const styles = await zip.file("word/styles.xml")!.async("string");
    for (const s of ['"Kop1"', '"Kop2"', '"Kop3"', '"Kop4"', '"Tabelraster"']) expect(styles).toContain(s);
    const xml = await zip.file("word/document.xml")!.async("string");
    expect(xml).toContain("<w:sectPr");
    expect(Object.keys(zip.files)).toContain("word/header1.xml");
    expect(Object.keys(zip.files)).toContain("word/footer1.xml");
  });

  it("zet 'Wijzigingen bijhouden' (track changes) aan", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const settings = await zip.file("word/settings.xml")!.async("string");
    expect(settings).toContain("<w:trackChanges");
  });

  it("behoudt de ECHTE 'informatie post akte'-tabel uit het sjabloon (geen platte-tekstversie ervan)", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const xml = await zip.file("word/document.xml")!.async("string");
    // De echte OOXML-tabel uit het sjabloon blijft behouden (geen platte tekst) —
    // de titeltekst "Informatie post akte" zit in het sjabloon over twee losse
    // <w:t>-runs ("Informati" + "e post akte"); "post akte" (kleine letters) zit
    // volledig in de tweede run en is dus een betrouwbaar, aaneengesloten anker.
    expect(xml).toContain("<w:tbl>");
    expect(xml).toContain("post akte");
    expect(xml).toContain("Volmacht NABAN");
    // ... en de platte-tekstversie ervan (onderdeel "hoofding-akte") is overgeslagen
    // (ALLE-HOOFDLETTERS-titel van de gegenereerde tekst, te onderscheiden van de
    // titel-case titel van de sjabloontabel hierboven).
    expect(xml).not.toContain("INFORMATIE POST AKTE");
    expect(xml).not.toContain("HOOFDING AKTE - INFORMATIE POST AKTE");
  });

  it("injecteert de volledige gegenereerde akte (met eigen openingsformule), zonder de sjabloon-ellips", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const xml = await zip.file("word/document.xml")!.async("string");
    // De eigen hoofding/openingsformule van de gegenereerde tekst staat er...
    expect(xml).toContain("VERKOOPAKTE ONROEREND GOED");
    expect(xml).toMatch(/HET JAAR/);
    // ... en de sjabloon-ellips-plaatshouder is NIET meer aanwezig (vervangen).
    expect(xml).not.toMatch(/<w:t[^>]*>…<\/w:t>/);
    // Werkblad met AI-instructies + pagina-einde vóór de akte.
    expect(xml).toContain("Nog aan te leveren gegevens");
    expect(xml).toContain('w:type="page"');
  });

  it("gebruikt echte SEQ-velden voor de clausulenummering (geen statisch gebakken volgnummer)", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const xml = await zip.file("word/document.xml")!.async("string");
    expect(xml).toContain("SEQ Clausule");
  });
});

describe("akte template-merge: kantoorlay-out overgenomen (FR)", () => {
  it("neemt het FR-sjabloon over met dezelfde benoemde stijlen en de ECHTE tabel", async () => {
    const zip = await akteDocx("schenkingsakte-onroerend-fr", "fr");
    const xml = await zip.file("word/document.xml")!.async("string");
    expect(xml).toContain("<w:sectPr");
    expect(xml).not.toMatch(/<w:t[^>]*>…<\/w:t>/);
    expect(xml).toContain("<w:tbl>");
    expect(xml).toContain("Information post acte");
    expect(xml).not.toContain("INFORMATION POST ACTE");
    expect(xml).not.toContain("EN-TÊTE DE L'ACTE - INFORMATION POST-ACTE");
    const styles = await zip.file("word/styles.xml")!.async("string");
    for (const s of ['"Kop1"', '"Kop2"', '"Kop3"', '"Kop4"']) expect(styles).toContain(s);
  });
});

describe("klikbare inhoudsopgave (backlog punt 31)", () => {
  it("NL: bevat een TOC-veld ná het werkblad en vóór de akte, met updateFields aan", async () => {
    const zip = await akteDocx("verkoopakte-woning", "nl");
    const xml = await zip.file("word/document.xml")!.async("string");
    expect(xml).toContain("Inhoudsopgave");
    expect(xml).toContain('TOC \\o "1-4" \\h \\z \\u');
    const posWerkblad = xml.indexOf("Nog aan te leveren gegevens");
    const posToc = xml.indexOf('TOC \\o "1-4"');
    const posAkte = xml.indexOf("VERKOOPAKTE ONROEREND GOED");
    expect(posWerkblad).toBeGreaterThan(-1);
    expect(posToc).toBeGreaterThan(posWerkblad);
    expect(posAkte).toBeGreaterThan(posToc);
    const settings = await zip.file("word/settings.xml")!.async("string");
    expect(settings).toContain('<w:updateFields w:val="true"/>');
  });

  it("FR: bevat 'Table des matières' als titel van het TOC-veld", async () => {
    const zip = await akteDocx("schenkingsakte-onroerend-fr", "fr");
    const xml = await zip.file("word/document.xml")!.async("string");
    expect(xml).toContain("Table des matières");
    expect(xml).toContain('TOC \\o "1-4" \\h \\z \\u');
  });
});

describe("akte template-merge: spellingtaal genormaliseerd (backlog punt 29)", () => {
  const docDefaultsTaal = async (zip: JSZip) => {
    const styles = await zip.file("word/styles.xml")!.async("string");
    const dd = styles.match(/<w:docDefaults>[\s\S]*?<\/w:docDefaults>/)?.[0] ?? "";
    return dd.match(/<w:lang\b[^>]*\bw:val="([^"]+)"/)?.[1] ?? "";
  };

  it("zet de docDefaults-taal op nl-BE voor een NL-akte", async () => {
    expect(await docDefaultsTaal(await akteDocx("verkoopakte-woning", "nl"))).toBe("nl-BE");
  });

  it("corrigeert de docDefaults-taal naar fr-BE voor een FR-akte (sjabloon stond op nl-BE)", async () => {
    expect(await docDefaultsTaal(await akteDocx("schenkingsakte-onroerend-fr", "fr"))).toBe("fr-BE");
  });
});
