// ── Gestructureerde Word-opmaak van een ontwerpdocument ─────────────────────
// Zet de platte ontwerptekst (genereerDocument) om naar Word-paragrafen met
// échte Word-stijlen ("koppen"), zodat het gegenereerde document dezelfde
// navigeerbare structuur krijgt als de kantoorlay-out:
//   • de documenttitel            → stijl "Titel" (Title)
//   • een sectiegroep "=== … ===" → stijl "Kop 1" (Heading 1)
//   • een onderdeel "N. TITEL"    → stijl "Kop 2" (Heading 2)
//   • een hypothese "▸ …"         → cursief
//   • overige regels              → gewone tekst
// De redactionele commentaren worden ster-gemarkeerd ("*[* … *]*") voor de
// Word-sneltoets. Bovenaan komt de kantoorhoofding, zodat het begin van elk
// (compromis)document overeenstemt met de kantoormodellen.

import { Paragraph, TextRun, ExternalHyperlink, HeadingLevel, AlignmentType, ImageRun, Footer, PageNumber, TableOfContents, type IStylesOptions, type ParagraphChild } from "docx";
import { KANTOOR, type Kantoor } from "@/data/kantoor";
import { sterMarkeerCommentaren } from "@/lib/word/markering";
import { segmenteer } from "@/lib/word/runs";
import { markeerWoordenlijst, type Taal } from "@/data/woordenlijst";
import { vertaalMarkeringenFR } from "@/data/modeldocumenten";
import { KANTOOR_LOGO, KANTOOR_LOGO_AFMETINGEN } from "@/lib/word/assets/kantoorLogo";

const GROEP_REGEL = /^=== (.+) ===$/;
const KOP_REGEL = /^## (.+)$/;
const SUBKOP_REGEL = /^### (.+)$/;
const SUBSUBKOP_REGEL = /^#### (.+)$/;
const HYPOTHESE_REGEL = /^▸ /;

/**
 * Documentstijlen die de kantoorlay-out benaderen: hoofdlettertype Calibri
 * (zoals het kantoormodel), koppen in Calibri Light met de overeenkomstige
 * groottes (Titel 28pt, Kop 1 16pt, Kop 2 14pt, Kop 3 12pt, Kop 4 11pt).
 * Vier niveaus zodat de clausulekop (Kop 2), de HOOFDLETTER-tussentitel
 * (Kop 3) en de fijnere tussentitel (Kop 4) elk hun eigen, correct geneste
 * niveau krijgen — nooit twee niveaus samengevoegd op dezelfde kopstijl.
 * Toepassen op elk gegenereerd .docx zodat het lettertype overeenstemt met
 * de kantoormodellen.
 */
/**
 * Bouwt de documentstijlen met de correcte spellingtaal (`w:lang`) als
 * standaard-runtaal, zodat Word de spellingcontrole in de JUISTE taal uitvoert
 * (Belgisch Nederlands `nl-BE` resp. Belgisch Frans `fr-BE`) in plaats van de
 * UI-standaardtaal (vaak `en-US`) — anders staat een volledig NL/FR-akte bij de
 * notaris vol foutieve rode kronkellijnen. Zonder argument: `nl-BE`.
 */
export function woordStijlen(taal: Taal = "nl"): IStylesOptions {
  const language = { value: taal === "fr" ? "fr-BE" : "nl-BE" };
  return {
    default: {
      // Uitvullen (justify) als standaardstijl, zoals de kantoormodellen; de
      // spellingtaal (w:lang) staat op de docDefaults-run zodat élke run ze erft.
      document: { run: { font: "Calibri", size: 22, language }, paragraph: { alignment: AlignmentType.JUSTIFIED } },
      // keepNext ("Op de volgende alinea laten aansluiten"/"bij volgende alinea
      // houden") op elke koppenstijl: een kop mag nooit als laatste regel
      // onderaan een pagina blijven staan, gescheiden van de tekst die erop
      // volgt. Geldt zo voor élk gegenereerd .docx (ontwerp én werkdossier),
      // want beide hergebruiken deze ene, gedeelde stijlendefinitie.
      title: { run: { font: "Calibri Light", size: 56, color: "1F1F1F" }, paragraph: { keepNext: true } },
      heading1: { run: { font: "Calibri Light", size: 32, bold: true, color: "1F1F1F" }, paragraph: { keepNext: true } },
      heading2: { run: { font: "Calibri Light", size: 28, bold: true, color: "1F1F1F" }, paragraph: { keepNext: true } },
      heading3: { run: { font: "Calibri Light", size: 24, bold: true, color: "1F1F1F" }, paragraph: { keepNext: true } },
      heading4: { run: { font: "Calibri Light", size: 22, bold: true, color: "1F1F1F" }, paragraph: { keepNext: true } },
    },
  };
}

/**
 * Gecentreerde paginavoettekst met een levend paginanummer-veld
 * ("Pagina X / Y" resp. "Page X / Y"). Word herberekent PAGE/NUMPAGES
 * automatisch, zodat een door de notaris gelezen of afgedrukt werkdocument
 * altijd correcte paginanummers draagt — de docx-library-uitvoer had er tot nu
 * geen (de sjabloon-merge erft de kantoorvoettekst wél).
 */
export function paginavoettekst(taal: Taal = "nl"): Footer {
  return new Footer({
    children: [
      new Paragraph({
        alignment: AlignmentType.CENTER,
        children: [
          new TextRun({ text: taal === "fr" ? "Page " : "Pagina ", size: 18 }),
          new TextRun({ children: [PageNumber.CURRENT], size: 18 }),
          new TextRun({ text: " / ", size: 18 }),
          new TextRun({ children: [PageNumber.TOTAL_PAGES], size: 18 }),
        ],
      }),
    ],
  });
}

/**
 * Klikbare, verversbare inhoudsopgave (TOC-veld, kopniveaus 1-4). Word
 * berekent paginanummers en koppelingen bij het openen (`features.updateFields`
 * op het Document, zie genereerOntwerpWordDocument.ts/
 * genereerWerkdossierWordDocument.ts) of handmatig met Ctrl+A F9.
 */
export function inhoudsopgaveParagraaf(taal: Taal = "nl"): TableOfContents {
  return new TableOfContents(taal === "fr" ? "Table des matières" : "Inhoudsopgave", {
    hyperlink: true,
    headingStyleRange: "1-4",
  });
}

/** Gecentreerde kantoorhoofding (briefhoofd) met logo bovenaan het document. */
export function kantoorHoofdingParagrafen(kantoor: Kantoor = KANTOOR): Paragraph[] {
  const regel = (tekst: string, bold = false) =>
    new Paragraph({
      alignment: AlignmentType.CENTER,
      children: [new TextRun({ text: tekst, bold, size: 24 })],
    });
  const regels: Paragraph[] = [];
  // Kantoorlogo gecentreerd bovenaan (schaalverhouding behouden, ±120px breed).
  if (KANTOOR_LOGO.length > 0) {
    const breedte = 120;
    const hoogte = Math.round((breedte * KANTOOR_LOGO_AFMETINGEN.hoogte) / KANTOOR_LOGO_AFMETINGEN.breedte);
    regels.push(
      new Paragraph({
        alignment: AlignmentType.CENTER,
        children: [new ImageRun({ type: "jpg", data: KANTOOR_LOGO, transformation: { width: breedte, height: hoogte } })],
      })
    );
  }
  regels.push(regel(kantoor.naam, true));
  if (kantoor.zetel) regels.push(regel(kantoor.zetel));
  const contact = [kantoor.telefoon ? `Tel. ${kantoor.telefoon}` : "", kantoor.email ?? ""].filter(Boolean).join(" — ");
  if (contact) regels.push(regel(contact));
  regels.push(new Paragraph({ text: "" }));
  return regels;
}

/**
 * Zet de ontwerptekst om naar Word-paragrafen met koppenstijlen. De eerste
 * niet-lege regel wordt als documenttitel (stijl "Titel") opgemaakt.
 */
export function ontwerpInhoudParagrafen(ontwerp: string, taal: Taal = "nl"): Paragraph[] {
  const paragrafen: Paragraph[] = [];
  let titelGezet = false;
  // FR-uitvoer: vertaal de interne werk-markeringen naar het Frans.
  const brontekst = taal === "fr" ? vertaalMarkeringenFR(ontwerp) : ontwerp;
  // Juridische begrippen krijgen (eerste keer) een hyperlink naar het woordenboek.
  for (const regel of markeerWoordenlijst(brontekst, taal).split("\n")) {
    if (regel.trim() === "") {
      paragrafen.push(new Paragraph({ text: "" }));
      continue;
    }
    const groep = regel.match(GROEP_REGEL);
    if (groep) {
      paragrafen.push(new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun({ text: groep[1], bold: true })] }));
      continue;
    }
    if (!titelGezet) {
      // Eerste inhoudelijke regel = documenttitel (genereerDocument zet de titel
      // van het model bovenaan, in hoofdletters).
      titelGezet = true;
      paragrafen.push(new Paragraph({ heading: HeadingLevel.TITLE, children: [new TextRun({ text: sterMarkeerCommentaren(regel) })] }));
      continue;
    }
    const subsubkop = regel.match(SUBSUBKOP_REGEL);
    if (subsubkop) {
      // Fijnere tussentitel: een echte Kop 4, genest onder de HOOFDLETTER-
      // tussentitel (Kop 3) resp. de clausulekop (Kop 2).
      paragrafen.push(new Paragraph({ heading: HeadingLevel.HEADING_4, children: [new TextRun({ text: subsubkop[1], bold: true })] }));
      continue;
    }
    const subkop = regel.match(SUBKOP_REGEL);
    if (subkop) {
      // HOOFDLETTER-tussentitel: een echte Kop 3, genest ONDER de clausulekop
      // (Kop 2) — nooit hetzelfde niveau, anders staan ze als gelijken naast
      // elkaar in de navigatie in plaats van genest.
      paragrafen.push(new Paragraph({ heading: HeadingLevel.HEADING_3, children: [new TextRun({ text: subkop[1], bold: true })] }));
      continue;
    }
    const kop = regel.match(KOP_REGEL);
    if (kop) {
      paragrafen.push(new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun({ text: kop[1], bold: true })] }));
      continue;
    }
    if (HYPOTHESE_REGEL.test(regel)) {
      // Hypothese-instructieregels worden cursief \u00E9n geel (te kiezen passage).
      paragrafen.push(new Paragraph({ children: tekstRuns(regel, 22, { italics: true }) }));
      continue;
    }
    paragrafen.push(new Paragraph({ children: tekstRuns(regel, 22) }));
  }
  return paragrafen;
}

/**
 * Bouwt de TextRuns van een regel: vet voor bedragen/namen (U+E000/U+E001),
 * gele arcering voor commentaarhaken en geel-gemarkeerde standaardverklaringen
 * (U+E002/U+E003). De ster-markering van commentaren gebeurt in segmenteer().
 */
function tekstRuns(regel: string, size: number, opties: { italics?: boolean } = {}): ParagraphChild[] {
  return segmenteer(regel).map((seg) => {
    if (seg.href) {
      // Hyperlink naar het woordenboek (blauw, onderlijnd).
      return new ExternalHyperlink({
        link: seg.href,
        children: [
          new TextRun({
            text: seg.text,
            size,
            bold: seg.vet,
            italics: opties.italics,
            color: "0563C1",
            underline: {},
            ...(seg.geel ? { highlight: "yellow" } : {}),
          }),
        ],
      });
    }
    return new TextRun({
      text: seg.text,
      size,
      bold: seg.vet,
      italics: opties.italics,
      ...(seg.onder ? { underline: {} } : {}),
      ...(seg.geel ? { highlight: "yellow" } : {}),
    });
  });
}
