// ── Server-side Word-export van een volledig werkdossier ────────────────────
// Bundelt het ingevulde ontwerpdocument, de ingevulde modelmail(s) en de
// afrekening in ÉÉN .docx-bestand, zodat de agent dat ongewijzigd kan
// doorgeven aan de gebruiker (zie AGENTS.md — einddoel: ontwerp + modelmail(s)
// + afrekening vormen samen het werkdossier). Hergebruikt dezelfde
// paragraaf-conventies als genereerOntwerpWordDocument.ts.

import { Document, Packer, Paragraph, TextRun, HeadingLevel, type Table, type TableOfContents } from "docx";
import { ontvangerRolLabels, type IngevuldeBrief } from "@/data/modelbrieven";
import { euro, pct } from "@/lib/format";
import type { AkteKostenOverzicht, HeffingResultaat } from "@/data/ereloon";
import type { BelastingResultaat } from "@/data/belastingen";
import { instructieSectieParagrafen, ontbrekendeGegevensParagrafen, structuurAnkerParagrafen, gebruikersNotitiesParagrafen, bijlageAfbeeldingenParagrafen, bevindingenParagrafen, bijgevoegdeStukkenParagrafen, type WerkdossierAfbeelding, type AgentBevinding } from "@/lib/word/aiAgentInstructies";
import { sterMarkeerCommentaren } from "@/lib/word/markering";
import { kantoorHoofdingParagrafen, ontwerpInhoudParagrafen, woordStijlen, paginavoettekst, inhoudsopgaveParagraaf } from "@/lib/word/ontwerpOpmaak";
import { forceerTrackChanges } from "@/lib/word/trackChanges";

function heading(tekst: string, niveau: typeof HeadingLevel.HEADING_1 | typeof HeadingLevel.HEADING_2): Paragraph {
  return new Paragraph({ heading: niveau, children: [new TextRun({ text: tekst, bold: true })] });
}

function tekstRegel(tekst: string, opties: { bold?: boolean; italics?: boolean } = {}): Paragraph {
  return new Paragraph({ children: [new TextRun({ text: tekst, size: 22, ...opties })] });
}

export interface WerkdossierBrief {
  titel: string;
  ingevuld: IngevuldeBrief;
}

export interface WerkdossierAfrekening {
  aktekosten?: { overzicht: AkteKostenOverzicht; gewest: string; akteType: string } | null;
  registratiebelasting?: { heffing: HeffingResultaat; gewest: string } | null;
  belasting?: { resultaat: BelastingResultaat; soort: string; gewest: string } | null;
}

export interface WerkdossierInhoud {
  modeldocumentTitel: string;
  ontwerp: string;
  brieven: WerkdossierBrief[];
  afrekening: WerkdossierAfrekening;
  /** Taal voor de werkblad-secties (ontbrekende stukken); standaard "nl". */
  taal?: "nl" | "fr";
  /** Vrije, door de gebruiker aangeleverde informatie (bv. via de Copilot Studio-chat), nuttig voor de afwerkende AI-agent maar zonder eigen {{parameter}}. */
  notitiesGebruiker?: string;
  /** Bijgevoegde schermafbeeldingen (PNG/JPEG, bv. stedenbouwkundige inlichtingen) — zie MAX_AANTAL_AFBEELDINGEN/MAX_AFBEELDING_BYTES. */
  afbeeldingen?: WerkdossierAfbeelding[];
  /**
   * Bevindingen van de voorbereidende (Copilot Studio-)agent: geïdentificeerde
   * parameters en nuttige informatie, mét zekerheidsgraad, zodat de afwerkende
   * Word-agent dubbelcheckt in plaats van alles opnieuw te identificeren.
   */
  bevindingen?: AgentBevinding[];
}

function aktekostenParagrafen(overzicht: AkteKostenOverzicht, gewest: string, akteType: string): Paragraph[] {
  return [
    heading(`Aktekosten/ereloon (${akteType}, ${gewest})`, HeadingLevel.HEADING_2),
    tekstRegel(`Erelonen/honorarium: ${euro(overzicht.honorarium)}`),
    tekstRegel(`Aktekost (barema ${overzicht.baremaCode}): ${euro(overzicht.aktekost)}`),
    tekstRegel(`Individualiseerbare kosten (incl. btw-plichtige opzoekingen): ${euro(overzicht.indBedrag)}`),
    tekstRegel(`Leveringskosten: ${euro(overzicht.levBedrag)}`),
    tekstRegel(`Btw-vrijgestelde kosten: ${euro(overzicht.vrijgesteldBedrag)}`),
    tekstRegel(`Subtotaal excl. btw: ${euro(overzicht.subtotaalExclBtw)}`),
    tekstRegel(`Btw: ${euro(overzicht.btw)}`),
    tekstRegel(`Totaal (excl. registratie-/schenkbelasting): ${euro(overzicht.totaal)}`, { bold: true }),
  ];
}

function registratiebelastingParagrafen(heffing: HeffingResultaat, gewest: string): Paragraph[] {
  return [
    heading(`Registratiebelasting (${gewest})`, HeadingLevel.HEADING_2),
    tekstRegel(`${heffing.label}: ${euro(heffing.bedrag)}`, { bold: true }),
    ...(heffing.opmerking ? [tekstRegel(heffing.opmerking)] : []),
  ];
}

function belastingParagrafen(resultaat: BelastingResultaat, soort: string, gewest: string): Paragraph[] {
  return [
    heading(`${soort === "schenking" ? "Schenkbelasting" : "Erfbelasting"} (${gewest})`, HeadingLevel.HEADING_2),
    ...resultaat.detail.map((d) =>
      tekstRegel(`Schijf t.e.m. ${euro(d.tot)}: ${euro(d.bedrag)} (${d.tarief}%)`)
    ),
    // pct: afgerond op 2 decimalen — de ruwe float (8.571428571428571%) hoort
    // niet in een document dat de notaris doorgeeft.
    tekstRegel(`Effectief tarief: ${pct(resultaat.effectiefTarief)}`),
    tekstRegel(`Totaal: ${euro(resultaat.totaal)}`, { bold: true }),
  ];
}

/** Bouwt één .docx-buffer met het ingevulde ontwerp, de modelmail(s) en de afrekening. */
export async function genereerWerkdossierWordDocument(inhoud: WerkdossierInhoud): Promise<Buffer> {
  const children: (Paragraph | Table | TableOfContents)[] = [
    heading("WERKDOSSIER — werkdocument, door de notaris na te lezen en te valideren", HeadingLevel.HEADING_1),
    new Paragraph({ text: "" }),
    ...instructieSectieParagrafen(),
    // Vlak na de prompt: de lijst van nog ontbrekende gegevens (uit het ontwerp).
    ...ontbrekendeGegevensParagrafen(inhoud.ontwerp, inhoud.taal ?? "nl"),
    // De vaste, lokaal berekende hoofdstukkenlijst — het anker voor de finale
    // zelfcontrole vóór oplevering (zie WERKDOSSIER_AGENT_PROMPT).
    ...structuurAnkerParagrafen(inhoud.ontwerp, inhoud.taal ?? "nl"),
    // Bevindingen van de voorbereidende agent (parameters + zekerheidsgraad),
    // zodat de Word-agent dubbelcheckt in plaats van opnieuw te identificeren.
    ...bevindingenParagrafen(inhoud.bevindingen, inhoud.taal ?? "nl"),
    // Stukkenmanifest: welke brondocumenten de bevindingen hierboven droegen,
    // zodat de Word-agent de overdracht van de stukken kan verifiëren.
    ...bijgevoegdeStukkenParagrafen(inhoud.bevindingen, inhoud.taal ?? "nl"),
    // Vrije, door de gebruiker aangeleverde informatie (indien aanwezig).
    ...gebruikersNotitiesParagrafen(inhoud.notitiesGebruiker, inhoud.taal ?? "nl"),
    // Bijgevoegde schermafbeeldingen (indien aanwezig).
    ...bijlageAfbeeldingenParagrafen(inhoud.afbeeldingen, inhoud.taal ?? "nl"),
  ];

  // Doorlopende sectienummering (sectie 1 = de instructies hierboven). De
  // modelmail(s) komen — op vraag — vlak na de ontbrekende gegevens en vóór het
  // ontwerp van compromis, zodat de notaris ze eerst kan klaarzetten/versturen.
  let sectie = 2;

  if (inhoud.brieven.length > 0) {
    children.push(heading(`${sectie++}. Modelmail(s)`, HeadingLevel.HEADING_1));
    for (const brief of inhoud.brieven) {
      children.push(heading(brief.titel, HeadingLevel.HEADING_2));
      children.push(tekstRegel(`Geadresseerde: ${ontvangerRolLabels[brief.ingevuld.rol]}`, { italics: true }));
      children.push(tekstRegel(`Onderwerp: ${sterMarkeerCommentaren(brief.ingevuld.onderwerp)}`, { bold: true }));
      children.push(...sterMarkeerCommentaren(brief.ingevuld.tekst).split("\n").map((r) => tekstRegel(r)));
      if (brief.ingevuld.bijlagen.length > 0) {
        children.push(tekstRegel(`Bijlagen: ${brief.ingevuld.bijlagen.join(", ")}`, { italics: true }));
      }
      children.push(new Paragraph({ text: "" }));
    }
  }

  children.push(heading(`${sectie++}. Ontwerpdocument — ${inhoud.modeldocumentTitel}`, HeadingLevel.HEADING_1));
  // Klikbare inhoudsopgave, ná de werkblad-/instructiepagina's en vóór de
  // akte zelf (features.updateFields hieronder vult ze bij het openen).
  children.push(inhoudsopgaveParagraaf(inhoud.taal ?? "nl"));
  children.push(new Paragraph({ text: "" }));
  // Kantoorhoofding (briefhoofd) + gestructureerde inhoud met koppenstijlen.
  children.push(...kantoorHoofdingParagrafen());
  children.push(...ontwerpInhoudParagrafen(inhoud.ontwerp, inhoud.taal ?? "nl"));
  children.push(new Paragraph({ text: "" }));

  if (inhoud.afrekening.aktekosten || inhoud.afrekening.registratiebelasting || inhoud.afrekening.belasting) {
    children.push(heading(`${sectie++}. Afrekening`, HeadingLevel.HEADING_1));
    if (inhoud.afrekening.aktekosten) {
      const { overzicht, gewest, akteType } = inhoud.afrekening.aktekosten;
      children.push(...aktekostenParagrafen(overzicht, gewest, akteType));
    }
    if (inhoud.afrekening.registratiebelasting) {
      const { heffing, gewest } = inhoud.afrekening.registratiebelasting;
      children.push(...registratiebelastingParagrafen(heffing, gewest));
    }
    if (inhoud.afrekening.belasting) {
      const { resultaat, soort, gewest } = inhoud.afrekening.belasting;
      children.push(...belastingParagrafen(resultaat, soort, gewest));
    }
  }

  const taal = inhoud.taal ?? "nl";
  const doc = new Document({
    styles: woordStijlen(taal),
    features: { trackRevisions: true, updateFields: true },
    // Documentmetadata (docProps/core.xml): de titel neemt de modeltitel over,
    // zodat de Word-bestandseigenschappen en het { TITLE }-veld het dossier
    // meteen benoemen.
    title: `${taal === "fr" ? "Dossier de travail" : "Werkdossier"} — ${inhoud.modeldocumentTitel}`,
    creator: "Notary.AI",
    lastModifiedBy: "Notary.AI",
    subject: taal === "fr" ? "Dossier de travail (document de travail)" : "Werkdossier (werkdocument)",
    keywords: "Notary.AI, werkdossier, ontwerp, modelmail, afrekening",
    sections: [{ footers: { default: paginavoettekst(taal) }, children }],
  });
  // features.trackRevisions schrijft zelf geen werkzaam OOXML-element (zie
  // trackChanges.ts) — forceer 'Wijzigingen bijhouden' na het genereren.
  return forceerTrackChanges(await Packer.toBuffer(doc));
}
