// ── Instructies voor de AI-agent die het werkdossier finaliseert ────────────
// Gedeelde, zelfstandige instructiesectie die bovenaan ELK gegenereerd
// .docx-bestand komt (zowel het losse ontwerp als het volledige werkdossier),
// zodat een willekeurige AI-agent met toegang tot de dossier-/identiteits-
// gegevens het document zelfstandig kan afwerken tot het einddoel (zie
// AGENTS.md). De instructies zijn defensief geformuleerd ("indien aanwezig"),
// zodat dezelfde tekst klopt of het document nu enkel een ontwerp bevat dan
// wel ook modelmail(s) en een afrekening.
// Alle TextRuns hier dragen noProof (w:noProof): dit zijn werkblad-/
// instructiepagina's die vóór gebruik worden verwijderd, dus Word hoeft er
// geen spelling op te controleren (geen rode kronkellijnen op prompttekst).

import { Paragraph, TextRun, HeadingLevel, ImageRun, AlignmentType, Table, TableRow, TableCell, WidthType } from "docx";
import { WERKDOSSIER_AGENT_PROMPT, WERKBLAD_KORTE_PROMPT } from "@/data/ai-prompts";
import { syntheseOntbrekendeDocumenten, type Prioriteit } from "@/lib/word/ontbrekendeDocumenten";
import { afmetingenUitBuffer, schaalNaarBreedte } from "@/lib/word/afbeeldingen";

/** Unieke {{parameter}}-namen die in de tekst nog als [AAN TE VULLEN: …] staan, in volgorde van verschijnen. */
export function ontbrekendeGegevensUitTekst(tekst: string): string[] {
  return [...new Set([...tekst.matchAll(/\[AAN TE VULLEN: ([^\]]+)\]/g)].map((m) => m[1].trim()))];
}

const PRIO_LABEL: Record<"nl" | "fr", Record<Prioriteit, string>> = {
  nl: { hoog: "HOOG", midden: "MIDDEN", laag: "LAAG" },
  fr: { hoog: "ÉLEVÉ", midden: "MOYEN", laag: "FAIBLE" },
};

const SECTIE_TITEL = { nl: "Nog aan te leveren gegevens", fr: "Éléments encore à fournir" } as const;
const DOC_TITEL = { nl: "Ontbrekende documenten (op prioriteit):", fr: "Documents manquants (par priorité) :" } as const;
const NIETS = {
  nl: "Alle gekende gegevens zijn ingevuld; er ontbreken geen documenten.",
  fr: "Toutes les données connues sont remplies ; aucun document ne manque.",
} as const;
const OVERIGE = { nl: "Overige nog in te vullen velden", fr: "Autres champs encore à compléter" } as const;

const NOTITIES_TITEL = {
  nl: "Aanvullende informatie van de gebruiker",
  fr: "Informations complémentaires transmises par l'utilisateur",
} as const;

/**
 * Bouwt, indien aanwezig, de sectie "Aanvullende informatie van de
 * gebruiker": vrije tekst die de gebruiker aan de Copilot Studio-agent heeft
 * meegegeven (bv. in de chat) en die nuttig is voor de AI-agent die het
 * document in Word M365 Copilot afwerkt, maar geen eigen {{parameter}} heeft.
 * Komt vlak na "Nog aan te leveren gegevens", zodat de Word-agent ze meteen
 * ziet. Leeg/ontbrekend → geen sectie (geen loze kop in het document).
 */
export function gebruikersNotitiesParagrafen(notities: string | undefined, taal: "nl" | "fr" = "nl"): Paragraph[] {
  const tekst = notities?.trim();
  if (!tekst) return [];
  return [
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ noProof: true, text: NOTITIES_TITEL[taal], bold: true })],
    }),
    ...tekst.split("\n").map((regel) =>
      regel.trim() === ""
        ? new Paragraph({ text: "" })
        : new Paragraph({ shading: { fill: INSTRUCTIE_ACHTERGROND }, children: [new TextRun({ noProof: true, text: regel, size: 22 })] })
    ),
    new Paragraph({ text: "" }),
  ];
}

/**
 * Bouwt de sectie "Nog aan te leveren gegevens": een opsomming van alle velden
 * die in het ontwerp nog ontbreken (de [AAN TE VULLEN: …]-plaatsen). Komt vlak
 * na de prompt zodat de AI-agent (of de notaris) meteen ziet welke informatie
 * nog moet worden aangeleverd om het werkdocument af te werken.
 */
export function ontbrekendeGegevensParagrafen(ontwerp: string, taal: "nl" | "fr" = "nl"): Paragraph[] {
  const ontbrekend = ontbrekendeGegevensUitTekst(ontwerp);
  const kop = new Paragraph({
    heading: HeadingLevel.HEADING_1,
    children: [new TextRun({ noProof: true, text: SECTIE_TITEL[taal], bold: true })],
  });
  if (ontbrekend.length === 0) {
    return [kop, new Paragraph({ children: [new TextRun({ noProof: true, text: NIETS[taal], size: 22 })] }), new Paragraph({ text: "" })];
  }
  const { documenten, overige } = syntheseOntbrekendeDocumenten(ontbrekend, taal);
  const regels: Paragraph[] = [kop];
  if (documenten.length > 0) {
    regels.push(new Paragraph({ children: [new TextRun({ noProof: true, text: DOC_TITEL[taal], bold: true, size: 22 })] }));
    for (const doc of documenten) {
      regels.push(
        new Paragraph({
          bullet: { level: 0 },
          children: [
            new TextRun({ noProof: true, text: `[${PRIO_LABEL[taal][doc.prioriteit]}] `, bold: true, size: 22 }),
            new TextRun({ noProof: true, text: doc.label, size: 22 }),
          ],
        })
      );
    }
  }
  if (overige.length > 0) {
    regels.push(new Paragraph({ children: [new TextRun({ noProof: true, text: `${OVERIGE[taal]}: ${overige.join(", ")}.`, size: 20, italics: true })] }));
  }
  regels.push(new Paragraph({ text: "" }));
  return regels;
}

// ── Structuuranker (finale-controlelijst tegen dubbele/verminkte nummering) ─
// De hoofdstukken van het ontwerp krijgen bij het genereren een doorlopende,
// letterlijke nummering ("## N. TITEL", zie genereerDocument). Vroeger
// gerapporteerde fouten (een dubbel geplakte slotclausule, een samengestelde
// nummer "1. 19." na een verwijdering) ontstonden pas NA generatie, tijdens
// het afwerken in Word M365 Copilot. Door die oorspronkelijke, correcte lijst
// hier — lokaal, zonder enige nieuwe data naar Notary.AI te sturen — als vaste
// checklist mee te geven, kan de afwerkende AI-agent (of de notaris) vlak vóór
// oplevering het EIGEN eindresultaat ertegen afzetten in plaats van enkel op
// het eigen zicht te vertrouwen.

/** Eén hoofdstuk (Kop 2) van het gegenereerde ontwerp: nummer + titel. */
export interface StructuurAnkerHoofdstuk {
  nummer: number;
  titel: string;
}

/**
 * Haalt de doorlopend genummerde hoofdstukken ("## N. TITEL") uit de
 * gegenereerde ontwerptekst, in volgorde — de brontekst van vóór eender welke
 * bewerking door een afwerkende AI-agent.
 */
export function structuurAnkerUitOntwerp(ontwerp: string): StructuurAnkerHoofdstuk[] {
  return [...ontwerp.matchAll(/^## (\d+)\. (.+)$/gm)].map((m) => ({ nummer: Number(m[1]), titel: m[2].trim() }));
}

const ANKER_TITEL = { nl: "Structuuranker (te controleren vóór oplevering)", fr: "Ancre de structure (à vérifier avant livraison)" } as const;
const ANKER_INTRO = {
  nl:
    "Dit is de oorspronkelijke, doorlopend genummerde hoofdstukkenlijst zoals Notary.AI ze genereerde, vóór enige bewerking. " +
    "Vergelijk vlak vóór oplevering de hoofdstukkenlijst van het AFGEWERKTE document hiermee: hetzelfde aantal, dezelfde volgorde en titels, " +
    "en een doorlopende nummering zonder gaten, dubbels of samengestelde nummers (bv. \"1. 19.\"). Wijkt dit af, herstel dan eerst de structuur/nummering — lever nooit een afwijkend resultaat stilzwijgend op.",
  fr:
    "Voici la liste originale, numérotée en continu, des chapitres telle que générée par Notary.AI, avant toute modification. " +
    "Juste avant la livraison, comparez la liste des chapitres du document FINALISÉ à celle-ci : même nombre, même ordre et mêmes titres, " +
    "et une numérotation continue sans trou, doublon ni numéro composé (par ex. « 1. 19. »). En cas d'écart, corrigez d'abord la structure/numérotation — ne livrez jamais un résultat divergent sans le signaler.",
} as const;
const ANKER_LEEG = {
  nl: "Geen genummerde hoofdstukken gevonden in het gegenereerde ontwerp.",
  fr: "Aucun chapitre numéroté trouvé dans le projet généré.",
} as const;

/**
 * Bouwt de sectie "Structuuranker": de vaste, lokaal berekende referentielijst
 * van hoofdstuknummers/-titels uit het net gegenereerde ontwerp. Leeg
 * ontwerp/geen hoofdstukken → toch de sectie met een duidelijke leeg-melding
 * (nooit stilzwijgend weglaten, want ontbreken kan zelf al een symptoom zijn).
 */
export function structuurAnkerParagrafen(ontwerp: string, taal: "nl" | "fr" = "nl"): Paragraph[] {
  const hoofdstukken = structuurAnkerUitOntwerp(ontwerp);
  const paragrafen: Paragraph[] = [
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ noProof: true, text: ANKER_TITEL[taal], bold: true })],
    }),
    new Paragraph({
      shading: { fill: INSTRUCTIE_ACHTERGROND },
      children: [new TextRun({ noProof: true, text: ANKER_INTRO[taal], size: 22 })],
    }),
  ];
  if (hoofdstukken.length === 0) {
    paragrafen.push(new Paragraph({ children: [new TextRun({ noProof: true, text: ANKER_LEEG[taal], italics: true, size: 20 })] }));
  } else {
    for (const h of hoofdstukken) {
      paragrafen.push(new Paragraph({ bullet: { level: 0 }, children: [new TextRun({ noProof: true, text: `${h.nummer}. ${h.titel}`, size: 20 })] }));
    }
  }
  paragrafen.push(new Paragraph({ text: "" }));
  return paragrafen;
}

export const INSTRUCTIE_ACHTERGROND = "FFF4CE";

/**
 * De instructietekst voor de AI-agent is één bron van waarheid: de
 * geoptimaliseerde Copilot-prompt WERKDOSSIER_AGENT_PROMPT (data/ai-prompts.ts),
 * die ook als afzonderlijke prompt in de prompt-module verschijnt. Hier wordt
 * ze, regel per regel, gerenderd als de eerste sectie van het .docx.
 */
export const INSTRUCTIES_AI_AGENT = WERKDOSSIER_AGENT_PROMPT;

/** True voor een sectiekop in de prompt (volledig in hoofdletters). */
function isSectieKop(regel: string): boolean {
  return !/^[-\d]/.test(regel) && /[A-ZÀ-Ý]/.test(regel) && regel === regel.toUpperCase();
}

function instructieRegel(regel: string): Paragraph {
  return new Paragraph({
    shading: { fill: INSTRUCTIE_ACHTERGROND },
    children: [new TextRun({ noProof: true, text: regel, size: 22, bold: isSectieKop(regel) })],
  });
}

/** Korte Word M365 Copilot-prompt (NL & FR) om bovenaan het document te tonen. */
export const KORTE_COPILOT_PROMPT: Record<"nl" | "fr", string> = {
  nl: WERKBLAD_KORTE_PROMPT,
  fr: `Vous êtes un collaborateur notarial expérimenté. Finalisez intégralement ce document — un dossier de travail Notary.AI — conformément aux instructions DÉTAILLÉES figurant sur la page de travail au début de ce document (« Instructions pour l'agent IA » et « Éléments encore à fournir »). Cette page de travail contient la méthode complète ; suivez-la scrupuleusement.

En bref : complétez le projet, le(s) modèle(s) de courriel et le décompte avec les données réelles du dossier, choisissez les hypothèses applicables et conservez l'intégralité du texte modèle, de la structure et de la mise en forme (n'inventez rien). Si la page de travail contient un tableau « Constatations de l'agent préparatoire », partez de ces paramètres identifiés (revérifiez-les brièvement selon leur degré de certitude — ne les identifiez pas à nouveau). Marquez avec *[* … *]* ce qui manque encore ([À COMPLÉTER]), ce qui est incertain ([À VÉRIFIER]) ou ce qui est à vérifier/supprimer ([À VÉRIFIER OU SUPPRIMER]).

Si vous pouvez préparer des courriels dans Outlook, créez-les comme brouillons (draft) et CONFIRMEZ expressément lesquels vous avez créés (destinataire + objet) ; ne les envoyez jamais vous-même.

Indiquez toujours expressément dans votre livraison si vous avez eu accès à tous les services Notary.AI et si vous avez rencontré des messages d'erreur de Notary.AI ; cherchez d'abord dans les pièces et via Notary.AI, ensuite seulement sur le web — et marquez expressément toute donnée issue du web comme source web.

Travaillez dans la langue du document. Ce document est la BASE du projet final : modifiez-le directement et supprimez TOUTES les sections de la page de travail (la courte instruction, les instructions, les informations complémentaires, la liste des éléments manquants, le tableau des constatations, le manifeste des pièces, les captures d'écran et l'ancre de structure) avant la livraison, pour ne conserver qu'un projet de document épuré. Conservez en revanche les marquages de fond ([À COMPLÉTER]/[À VÉRIFIER]/[À VÉRIFIER OU SUPPRIMER], surlignage jaune) pour le notaire.`,
};

const KORTE_PROMPT_TITEL = {
  nl: "Te kopiëren in Word M365 Copilot:",
  fr: "À copier dans Word M365 Copilot :",
} as const;

/**
 * Bouwt, als allereerste inhoud van het .docx, de korte prompt die de gebruiker
 * letterlijk in Word M365 Copilot plakt. Die korte prompt verwijst naar de
 * gedetailleerde werkbladinstructies die er meteen onder volgen.
 */
export function korteCopilotPromptParagrafen(taal: "nl" | "fr" = "nl"): Paragraph[] {
  return [
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ noProof: true, text: KORTE_PROMPT_TITEL[taal], bold: true })],
    }),
    ...KORTE_COPILOT_PROMPT[taal].split("\n").map((regel) =>
      regel.trim() === ""
        ? new Paragraph({ text: "" })
        : new Paragraph({
            shading: { fill: INSTRUCTIE_ACHTERGROND },
            children: [new TextRun({ noProof: true, text: regel, size: 22 })],
          })
    ),
    new Paragraph({ text: "" }),
  ];
}

/**
 * Bouwt de instructiesectie ("1. Instructies voor de AI Agent") als paragrafen,
 * klaar om bovenaan een .docx te plaatsen. De prompt wordt regel per regel
 * weergegeven (sectiekoppen in het vet); de afsluitende lege paragraaf zorgt
 * voor witruimte vóór de eerstvolgende sectie.
 */
export function instructieSectieParagrafen(): Paragraph[] {
  return [
    ...korteCopilotPromptParagrafen("nl"),
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ noProof: true, text: "1. Instructies voor de AI Agent", bold: true })],
    }),
    ...WERKDOSSIER_AGENT_PROMPT.split("\n").map((regel) =>
      regel.trim() === "" ? new Paragraph({ text: "" }) : instructieRegel(regel)
    ),
    new Paragraph({ text: "" }),
  ];
}

// ── Bevindingen van de voorbereidende (Copilot Studio-)agent ────────────────
// De agent die het werkdossier genereert, heeft de dossierstukken al gelezen
// en parameters/nuttige informatie geïdentificeerd. Door die bevindingen —
// mét zekerheidsgraad per parameter — in het document mee te geven, hoeft de
// AI-agent die het document in Word M365 Copilot afwerkt dat werk niet
// opnieuw te doen: hij controleert (dubbelcheckt) en vult in, in plaats van
// alles opnieuw te identificeren.

/** Eén bevinding van de voorbereidende agent: een geïdentificeerde parameter met zekerheidsgraad. */
export interface AgentBevinding {
  /** De {{parameter}}-naam of het gegeven waarop de bevinding slaat. */
  parameter: string;
  /** De geïdentificeerde waarde (per GDPR-conventie geldt de invoer als geanonimiseerd). */
  waarde: string;
  /** Zekerheidsgraad: percentage (bv. 95 of "95%") of kwalificatie ("hoog"/"middel"/"laag"). */
  zekerheid?: string | number;
  /** Bron van de bevinding (bv. "compromis p. 2", "EPC-attest"). */
  bron?: string;
  /** Vrije toelichting. */
  toelichting?: string;
}

/** Maximaal aantal bevindingen per werkdossier (ruim boven elk realistisch dossier). */
export const MAX_AANTAL_BEVINDINGEN = 200;

const BEVINDINGEN_TITEL = {
  nl: "Bevindingen van de voorbereidende agent",
  fr: "Constatations de l'agent préparatoire",
} as const;
const BEVINDINGEN_INTRO = {
  nl:
    "De voorbereidende agent identificeerde onderstaande parameters en informatie in de dossierstukken, telkens met zijn zekerheidsgraad. " +
    "Gebruik deze bevindingen als vertrekpunt — identificeer ze niet opnieuw: dubbelcheck ze kort tegen de stukken (verplicht bij een zekerheid onder de 90% of zonder bron) en vul ze dan in. " +
    "Wijkt een stuk af van een bevinding, dan primeert het stuk; markeer de afwijking als [TE VERIFIËREN].",
  fr:
    "L'agent préparatoire a identifié dans les pièces du dossier les paramètres et informations ci-dessous, chacun avec son degré de certitude. " +
    "Utilisez ces constatations comme point de départ — ne les identifiez pas à nouveau : revérifiez-les brièvement (obligatoire si la certitude est inférieure à 90% ou sans source), puis complétez. " +
    "Si une pièce contredit une constatation, la pièce prime ; marquez l'écart comme [À VÉRIFIER].",
} as const;
const BEVINDINGEN_KOLOMMEN = {
  nl: ["Parameter", "Waarde", "Zekerheid", "Bron / toelichting"],
  fr: ["Paramètre", "Valeur", "Certitude", "Source / commentaire"],
} as const;
const BEVINDING_ONGELDIG = {
  nl: "[NAKIJKEN: één of meer bevindingen van de voorbereidende agent waren onvolledig (parameter of waarde ontbrak) en zijn weggelaten.]",
  fr: "[À VÉRIFIER : une ou plusieurs constatations de l'agent préparatoire étaient incomplètes (paramètre ou valeur manquant) et ont été omises.]",
} as const;
const BEVINDINGEN_GEEN = {
  nl:
    "Geen bevindingen aangeleverd door de voorbereidende agent — identificeer alle parameters zelf vanaf nul, " +
    "rechtstreeks uit de aangeleverde stukken (er is géén voorwerk om op verder te bouwen).",
  fr:
    "Aucune constatation fournie par l'agent préparatoire — identifiez vous-même tous les paramètres à partir de zéro, " +
    "directement dans les pièces fournies (il n'y a aucun travail préparatoire sur lequel s'appuyer).",
} as const;

/** Zekerheidsgraad leesbaar maken: 95 → "95 %", "95%" → "95%", "hoog" → "hoog", leeg → "—". */
function zekerheidTekst(zekerheid: string | number | undefined): string {
  if (zekerheid === undefined || zekerheid === null || zekerheid === "") return "—";
  if (typeof zekerheid === "number") return `${zekerheid} %`;
  return zekerheid;
}

function bevindingCel(tekst: string, opties: { bold?: boolean } = {}): TableCell {
  return new TableCell({
    children: [new Paragraph({ children: [new TextRun({ noProof: true, text: tekst, size: 20, ...opties })] })],
  });
}

/**
 * Bouwt de sectie "Bevindingen van de voorbereidende agent": een tabel met per
 * geïdentificeerde parameter de waarde, de zekerheidsgraad en de
 * bron/toelichting. Onvolledige bevindingen (zonder parameter of waarde)
 * worden overgeslagen mét één duidelijke markering — de generatie wordt nooit
 * geweigerd. Leeg/ontbrekend → de sectie verschijnt tóch, met de expliciete
 * melding dat er geen bevindingen zijn aangeleverd (agent 2 leidt "vanaf nul
 * identificeren" nooit impliciet uit een afwezige tabel af — zie
 * OVERDRACHT-TWEE-AGENTS.md).
 */
export function bevindingenParagrafen(
  bevindingen: AgentBevinding[] | undefined,
  taal: "nl" | "fr" = "nl"
): (Paragraph | Table)[] {
  if (!bevindingen || bevindingen.length === 0) {
    return [
      new Paragraph({
        heading: HeadingLevel.HEADING_1,
        children: [new TextRun({ noProof: true, text: BEVINDINGEN_TITEL[taal], bold: true })],
      }),
      new Paragraph({
        shading: { fill: INSTRUCTIE_ACHTERGROND },
        children: [new TextRun({ noProof: true, text: BEVINDINGEN_GEEN[taal], size: 22, bold: true })],
      }),
      new Paragraph({ text: "" }),
    ];
  }
  const geldig = bevindingen
    .slice(0, MAX_AANTAL_BEVINDINGEN)
    .filter((b) => typeof b?.parameter === "string" && b.parameter.trim() !== "" && typeof b?.waarde === "string" && b.waarde.trim() !== "");
  const overgeslagen = Math.min(bevindingen.length, MAX_AANTAL_BEVINDINGEN) - geldig.length;

  const blokken: (Paragraph | Table)[] = [
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ noProof: true, text: BEVINDINGEN_TITEL[taal], bold: true })],
    }),
    new Paragraph({
      shading: { fill: INSTRUCTIE_ACHTERGROND },
      children: [new TextRun({ noProof: true, text: BEVINDINGEN_INTRO[taal], size: 22 })],
    }),
    new Paragraph({ text: "" }),
  ];
  if (geldig.length > 0) {
    blokken.push(
      new Table({
        width: { size: 100, type: WidthType.PERCENTAGE },
        rows: [
          new TableRow({ children: BEVINDINGEN_KOLOMMEN[taal].map((kop) => bevindingCel(kop, { bold: true })) }),
          ...geldig.map(
            (b) =>
              new TableRow({
                children: [
                  bevindingCel(b.parameter.trim()),
                  bevindingCel(b.waarde.trim()),
                  bevindingCel(zekerheidTekst(b.zekerheid)),
                  bevindingCel([b.bron?.trim(), b.toelichting?.trim()].filter(Boolean).join(" — ") || "—"),
                ],
              })
          ),
        ],
      })
    );
  }
  if (overgeslagen > 0) {
    blokken.push(new Paragraph({ children: [new TextRun({ noProof: true, text: BEVINDING_ONGELDIG[taal], bold: true, size: 20 })] }));
  }
  blokken.push(new Paragraph({ text: "" }));
  return blokken;
}

// ── Geraadpleegde brondocumenten (stukkenmanifest) ──────────────────────────
// Agent 2 krijgt enkel het .docx + de stukken, zonder enige andere context
// (zie OVERDRACHT-TWEE-AGENTS.md). De server-side generatie ontvangt zelf
// nooit een volledig dossier (GDPR: enkel geanonimiseerde kenmerken/parameters
// bereiken Notary.AI) — het enige beschikbare signaal over WELKE brondocumenten
// agent 1 gebruikte, is het optionele `bron`-veld per bevinding
// (AgentBevinding.bron, bv. "compromis p. 2", "EPC-attest"). Deze sectie
// herleidt daaruit een kort manifest, zodat agent 2 kan nagaan of de overdracht
// van de stukken (bijlage) volledig was vóór hij verdergaat.

const STUKKEN_TITEL = {
  nl: "Geraadpleegde brondocumenten",
  fr: "Documents sources consultés",
} as const;
const STUKKEN_INTRO = {
  nl:
    "De voorbereidende agent baseerde de bevindingen hierboven op onderstaande brondocumenten. " +
    "Controleer dat je exact deze stukken als bijlage ontving vóór je verdergaat — ontbreekt er één, vraag ze dan op.",
  fr:
    "L'agent préparatoire a fondé les constatations ci-dessus sur les documents sources ci-dessous. " +
    "Vérifiez que vous avez bien reçu exactement ces pièces en annexe avant de continuer — s'il en manque une, demandez-la.",
} as const;
const STUKKEN_LEEG = {
  nl: "Geen brondocumenten vermeld bij de bevindingen — ga bij de gebruiker na welke stukken werden aangeleverd.",
  fr: "Aucun document source mentionné dans les constatations — vérifiez auprès de l'utilisateur quelles pièces ont été fournies.",
} as const;

/**
 * Bouwt, wanneer er bevindingen zijn, de sectie "Geraadpleegde brondocumenten":
 * de unieke, niet-lege `bron`-vermeldingen uit de bevindingen, in volgorde van
 * eerste voorkomen. Bevindingen zonder enige `bron` → een expliciete
 * leeg-melding (nooit stilzwijgend weglaten: dat kan zelf al een signaal zijn
 * dat de bevindingen niet aan brondocumenten te koppelen waren). Geen
 * bevindingen → geen sectie (niets om uit af te leiden).
 */
export function bijgevoegdeStukkenParagrafen(bevindingen: AgentBevinding[] | undefined, taal: "nl" | "fr" = "nl"): Paragraph[] {
  if (!bevindingen || bevindingen.length === 0) return [];
  const stukken = [...new Set(bevindingen.map((b) => b.bron?.trim()).filter((b): b is string => !!b))];
  const kop = new Paragraph({
    heading: HeadingLevel.HEADING_1,
    children: [new TextRun({ noProof: true, text: STUKKEN_TITEL[taal], bold: true })],
  });
  if (stukken.length === 0) {
    return [kop, new Paragraph({ children: [new TextRun({ noProof: true, text: STUKKEN_LEEG[taal], italics: true, size: 20 })] }), new Paragraph({ text: "" })];
  }
  return [
    kop,
    new Paragraph({ shading: { fill: INSTRUCTIE_ACHTERGROND }, children: [new TextRun({ noProof: true, text: STUKKEN_INTRO[taal], size: 22 })] }),
    ...stukken.map((s) => new Paragraph({ bullet: { level: 0 }, children: [new TextRun({ noProof: true, text: s, size: 22 })] })),
    new Paragraph({ text: "" }),
  ];
}

// ── Bijgevoegde schermafbeeldingen (bv. stedenbouwkundige inlichtingen) ─────
// De gebruiker kan via de Copilot Studio-chat schermafbeeldingen (PNG/JPEG)
// aanleveren die letterlijk in het werkdossier moeten verschijnen (bv. de
// pagina's van een ontvangen PDF met stedenbouwkundige inlichtingen), zodat
// de AI-agent die het document in Word M365 Copilot afwerkt de inhoud ervan
// kan overnemen. Bewuste, lage limieten: dit gaat via de POST-body (base64),
// niet via de query-string, en base64 verdrievoudigt de payload in tekens.

/** Eén bijgevoegde afbeelding: bestandsnaam, base64-inhoud (zonder data-URL-voorvoegsel) en optioneel bijschrift. */
export interface WerkdossierAfbeelding {
  bestandsnaam: string;
  base64: string;
  bijschrift?: string;
}

/** Maximaal aantal bijgevoegde afbeeldingen per werkdossier. */
export const MAX_AANTAL_AFBEELDINGEN = 10;
/** Maximale grootte (bytes, gedecodeerd) per afbeelding — ruim voldoende voor een schermafbeelding. */
export const MAX_AFBEELDING_BYTES = 5_000_000;
/** Maximale weergavebreedte (pixels) — een gangbare leesbare breedte in het document. */
const MAX_WEERGAVEBREEDTE = 550;

const BIJLAGEN_TITEL = {
  nl: "Bijgevoegde schermafbeeldingen",
  fr: "Captures d'écran jointes",
} as const;
const AFBEELDING_OVERGESLAGEN = {
  nl: (naam: string) => `[NAKIJKEN: afbeelding "${naam}" kon niet worden ingevoegd (onherkend formaat of te groot) — vraag de gebruiker om ze rechtstreeks te plakken of opnieuw aan te leveren.]`,
  fr: (naam: string) => `[À VÉRIFIER : l'image "${naam}" n'a pas pu être insérée (format non reconnu ou trop volumineux) — demandez à l'utilisateur de la coller directement ou de la fournir à nouveau.]`,
} as const;

/**
 * Bouwt, indien aanwezig, de sectie "Bijgevoegde schermafbeeldingen": elke
 * geldige PNG/JPEG wordt ingevoegd (geschaald op leesbare breedte, met
 * behoud van de beeldverhouding) met haar bijschrift; een afbeelding die niet
 * gelezen kan worden (onherkend formaat, corrupte data) wordt overgeslagen
 * mét een duidelijke markering, zodat de agent het nooit stilzwijgend mist.
 * Leeg/ontbrekend → geen sectie.
 */
export function bijlageAfbeeldingenParagrafen(afbeeldingen: WerkdossierAfbeelding[] | undefined, taal: "nl" | "fr" = "nl"): Paragraph[] {
  if (!afbeeldingen || afbeeldingen.length === 0) return [];
  const paragrafen: Paragraph[] = [
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ noProof: true, text: BIJLAGEN_TITEL[taal], bold: true })],
    }),
  ];
  for (const afbeelding of afbeeldingen.slice(0, MAX_AANTAL_AFBEELDINGEN)) {
    let buffer: Buffer;
    try {
      buffer = Buffer.from(afbeelding.base64, "base64");
    } catch {
      paragrafen.push(new Paragraph({ children: [new TextRun({ noProof: true, text: AFBEELDING_OVERGESLAGEN[taal](afbeelding.bestandsnaam), bold: true })] }));
      continue;
    }
    const afmetingen = buffer.length > 0 && buffer.length <= MAX_AFBEELDING_BYTES ? afmetingenUitBuffer(buffer) : null;
    if (!afmetingen) {
      paragrafen.push(new Paragraph({ children: [new TextRun({ noProof: true, text: AFBEELDING_OVERGESLAGEN[taal](afbeelding.bestandsnaam), bold: true })] }));
      continue;
    }
    const { breedte, hoogte } = schaalNaarBreedte(afmetingen.breedte, afmetingen.hoogte, MAX_WEERGAVEBREEDTE);
    paragrafen.push(
      new Paragraph({
        alignment: AlignmentType.CENTER,
        children: [new ImageRun({ type: afmetingen.type, data: buffer, transformation: { width: breedte, height: hoogte } })],
      })
    );
    if (afbeelding.bijschrift?.trim()) {
      paragrafen.push(new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({ noProof: true, text: afbeelding.bijschrift.trim(), italics: true, size: 20 })] }));
    } else {
      paragrafen.push(new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({ noProof: true, text: afbeelding.bestandsnaam, italics: true, size: 20 })] }));
    }
    paragrafen.push(new Paragraph({ text: "" }));
  }
  return paragrafen;
}
