// ── Platte tekst uit een aangeleverd .docx-bestand halen ─────────────────────
// Het conventie-nazicht ontvangt het ontwerp van de wederpartij meestal als
// Word-bestand. Voor de analyse volstaat de platte tekst: elke `w:p` wordt een
// regel, `w:t`-inhoud wordt overgenomen, tabs en regeleinden binnen een alinea
// blijven behouden. Reeds aanwezige revisies in het bronbestand worden gelezen
// alsof ze aanvaard zijn (`w:delText` — geschrapte tekst — wordt overgeslagen,
// invoegingen tellen gewoon mee): het nazicht toetst wat de tekst ná de
// wijzigingen van de wederpartij zegt.
//
// Bewust een lichte, regex-gebaseerde extractie (geen extra dependency zoals
// mammoth): opmaak en structuur mogen verloren gaan, de woorden niet.

import JSZip from "jszip";

/** Decodeert de vijf XML-basisentiteiten en numerieke entiteiten. */
function decodeerXmlEntiteiten(tekst: string): string {
  return tekst
    .replace(/&#x([0-9a-fA-F]+);/g, (_, hex: string) => String.fromCodePoint(parseInt(hex, 16)))
    .replace(/&#(\d+);/g, (_, dec: string) => String.fromCodePoint(parseInt(dec, 10)))
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">")
    .replace(/&quot;/g, '"')
    .replace(/&apos;/g, "'")
    .replace(/&amp;/g, "&");
}

/** Haalt de zichtbare tekst uit de XML van één alinea (`w:p`-fragment). */
function alineaTekst(fragment: string): string {
  let uit = "";
  const regex = /<w:t(?:\s[^>]*)?>([\s\S]*?)<\/w:t>|<w:tab\s*\/>|<w:br\s*\/>/g;
  let match: RegExpExecArray | null;
  while ((match = regex.exec(fragment)) !== null) {
    if (match[0].startsWith("<w:tab")) uit += "\t";
    else if (match[0].startsWith("<w:br")) uit += "\n";
    else uit += decodeerXmlEntiteiten(match[1]);
  }
  return uit;
}

/**
 * Extraheert de platte tekst uit een .docx-bestand (ArrayBuffer, zoals
 * `File.arrayBuffer()` in de browser oplevert). Gooit een duidelijke fout
 * wanneer het bestand geen Word-document is.
 */
export async function extraheerTekstUitDocx(bestand: ArrayBuffer): Promise<string> {
  let zip: JSZip;
  try {
    zip = await JSZip.loadAsync(bestand);
  } catch {
    throw new Error("Het bestand kon niet worden gelezen als .docx (geen geldig zip-archief).");
  }
  const document = zip.file("word/document.xml");
  if (!document) {
    throw new Error("Het bestand bevat geen word/document.xml — is dit wel een .docx?");
  }
  const xml = await document.async("string");
  // Geschrapte tekst uit bestaande revisies weglaten: lezen alsof aanvaard.
  const zonderSchrappingen = xml.replace(/<w:delText(?:\s[^>]*)?>[\s\S]*?<\/w:delText>/g, "");
  return zonderSchrappingen
    .split(/<\/w:p>/)
    .map(alineaTekst)
    .join("\n")
    .replace(/\n{3,}/g, "\n\n")
    .trim();
}
