// ── Conventie-nazicht → .docx met échte Word-revisies (track changes) ────────
// Zet een NazichtRapport (lib/conventie-nazicht/analyse.ts) om in een Word-
// document waarin élk voorstel een echte OOXML-revisie is (`w:del`/`w:ins`,
// auteur "Notary.AI"): de notaris opent het bestand en aanvaardt of verwerpt
// elk punt afzonderlijk via de gewone Controleren-lint. De originele tekst
// van de wederpartij blijft integraal behouden; alles wat Notary.AI wijzigt,
// is zichtbaar en omkeerbaar — het resultaat blijft een werkdocument dat de
// notaris naleest en valideert (BETA).
//
// Motiveringen staan inline als geel gearceerde `*[*…*]*`-commentaren binnen
// de invoeging (huisconventie: de kantoor-sneltoets springt naar `*`); wie
// het commentaar niet wil behouden, verwerpt die revisie gewoon mee.

import {
  AlignmentType,
  DeletedTextRun,
  Document,
  HeadingLevel,
  InsertedTextRun,
  Packer,
  Paragraph,
  TextRun,
} from "docx";
import type { NazichtBevinding, NazichtRapport } from "@/lib/conventie-nazicht/analyse";
import { splitsAlineas } from "@/lib/conventie-nazicht/analyse";
import { nazichtCategorieLabels } from "@/data/conventie-nazicht/types";
import { woordStijlen, paginavoettekst } from "@/lib/word/ontwerpOpmaak";
import { segmenteer } from "@/lib/word/runs";
import { forceerTrackChanges } from "@/lib/word/trackChanges";
import { KANTOOR } from "@/data/kantoor";

export interface NazichtWordOpties {
  /** De originele, extern ontvangen ontwerptekst. */
  tekst: string;
  rapport: NazichtRapport;
  /** Revisie-auteur zoals Word die toont. */
  auteur?: string;
  /** Revisiedatum (ISO); expliciet aan te leveren voor determinisme in tests. */
  datumIso: string;
}

const AUTEUR_STANDAARD = "Notary.AI";
const TEKST_GROOTTE = 22; // 11pt, conform de documentstandaard (woordStijlen)

/** Doorlopende revisie-id's: elk `w:ins`/`w:del` moet een uniek id dragen. */
function maakIdTeller(): () => number {
  let id = 0;
  return () => ++id;
}

/**
 * Zet een voorsteltekst om in InsertedTextRun-runs: `[ … ]`-passages worden
 * geel gearceerd en ster-gemarkeerd (via de gedeelde run-segmentatie), zodat
 * open plekken en motiveringen dezelfde opmaak dragen als elk ander
 * kantoordocument.
 */
function invoegRuns(
  tekst: string,
  revisie: { auteur: string; datumIso: string; volgendId: () => number }
): InsertedTextRun[] {
  return segmenteer(tekst).map(
    (seg) =>
      new InsertedTextRun({
        text: seg.text,
        size: TEKST_GROOTTE,
        ...(seg.vet ? { bold: true } : {}),
        ...(seg.geel ? { highlight: "yellow" } : {}),
        id: revisie.volgendId(),
        author: revisie.auteur,
        date: revisie.datumIso,
      })
  );
}

/** Korte, geel gearceerde motivering die met de revisie mee aanvaard/verworpen wordt. */
function motiveringTekst(bevinding: NazichtBevinding): string {
  const label = nazichtCategorieLabels[bevinding.punt.categorie].toUpperCase();
  const wetsbasis = bevinding.punt.wetsbasis?.length
    ? ` (${bevinding.punt.wetsbasis.join("; ")})`
    : "";
  return ` [${label} — ${bevinding.punt.titel}: ${bevinding.punt.uitleg}${wetsbasis}]`;
}

/**
 * Bouwt het nazichtdocument (docx-Document, nog niet verpakt): overzicht van
 * de bevindingen, daarna de integrale tekst met revisies per alinea, en tot
 * slot de in te voegen clausules voor de ontbrekende punten.
 */
export function maakNazichtDocument(opties: NazichtWordOpties): Document {
  const auteur = opties.auteur ?? AUTEUR_STANDAARD;
  const volgendId = maakIdTeller();
  const revisie = { auteur, datumIso: opties.datumIso, volgendId };

  const alineas = splitsAlineas(opties.tekst);
  const perAlinea = new Map<number, NazichtBevinding[]>();
  for (const bevinding of opties.rapport.actiepunten) {
    if (bevinding.paragraafIndex === undefined) continue;
    const lijst = perAlinea.get(bevinding.paragraafIndex) ?? [];
    lijst.push(bevinding);
    perAlinea.set(bevinding.paragraafIndex, lijst);
  }
  const inTeVoegen = opties.rapport.actiepunten.filter((b) => b.actie === "invoegen");

  const kinderen: Paragraph[] = [];

  // ── Werkblad: titel + samenvatting (blijft gewone tekst, geen revisie) ────
  kinderen.push(
    new Paragraph({
      heading: HeadingLevel.TITLE,
      children: [new TextRun({ text: "Nazicht ontwerpconventie — wijzigingsvoorstellen" })],
    }),
    new Paragraph({
      alignment: AlignmentType.LEFT,
      children: [
        new TextRun({
          text:
            `Rechtshandeling: ${opties.rapport.akteType} · Nazicht door ${auteur} (BETA) · ` +
            `${KANTOOR.naam}, ${KANTOOR.standplaats}. Elk voorstel staat als bijgehouden wijziging in de tekst: ` +
            `aanvaard of verwerp per punt via het Controleren-lint. Dit werkdocument vervangt ` +
            `het nazicht door de notaris niet.`,
          size: 20,
          noProof: true,
        }),
      ],
    }),
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ text: "Overzicht van de bevindingen", bold: true })],
    })
  );

  if (opties.rapport.actiepunten.length === 0) {
    kinderen.push(
      new Paragraph({
        children: [
          new TextRun({
            text: "Geen afwijkingen van de kennisbank gevonden voor deze rechtshandeling.",
            size: TEKST_GROOTTE,
            noProof: true,
          }),
        ],
      })
    );
  }
  for (const bevinding of opties.rapport.actiepunten) {
    const actieLabel =
      bevinding.actie === "invoegen"
        ? "ontbreekt → clausule ingevoegd achteraan"
        : bevinding.actie === "vervangen"
          ? "aangetroffen → alinea vervangen"
          : "aangetroffen → alinea geschrapt";
    kinderen.push(
      new Paragraph({
        alignment: AlignmentType.LEFT,
        children: [
          new TextRun({
            text: `• [${nazichtCategorieLabels[bevinding.punt.categorie]}] ${bevinding.punt.titel} — ${actieLabel}`,
            size: 20,
            noProof: true,
          }),
        ],
      })
    );
  }

  // ── De originele tekst, alinea per alinea, met revisies ──────────────────
  kinderen.push(
    new Paragraph({
      heading: HeadingLevel.HEADING_1,
      children: [new TextRun({ text: "Tekst van de conventie met wijzigingsvoorstellen", bold: true })],
    })
  );

  alineas.forEach((alinea, index) => {
    const bevindingen = perAlinea.get(index);
    if (!bevindingen || alinea.trim() === "") {
      kinderen.push(
        new Paragraph({
          children: alinea === "" ? [] : [new TextRun({ text: alinea, size: TEKST_GROOTTE })],
        })
      );
      return;
    }

    // De getroffen alinea integraal als schrapping, gevolgd door de
    // vervangtekst en de motivering als invoeging — één alinea, zodat de
    // notaris beide kanten van het voorstel naast elkaar ziet.
    const runs: (DeletedTextRun | InsertedTextRun)[] = [
      new DeletedTextRun({
        text: alinea,
        size: TEKST_GROOTTE,
        id: volgendId(),
        author: auteur,
        date: opties.datumIso,
      }),
    ];
    for (const bevinding of bevindingen) {
      if (bevinding.punt.vervanging) {
        runs.push(...invoegRuns(` ${bevinding.punt.vervanging}`, revisie));
      }
      runs.push(...invoegRuns(motiveringTekst(bevinding), revisie));
    }
    kinderen.push(new Paragraph({ children: runs }));
  });

  // ── Ontbrekende clausules: integraal als invoeging achteraan ─────────────
  if (inTeVoegen.length > 0) {
    kinderen.push(
      new Paragraph({
        children: invoegRuns(
          "AANVULLENDE CLAUSULES (voorstel Notary.AI — op de juiste plaats in de conventie in te schuiven)",
          revisie
        ),
      })
    );
    for (const bevinding of inTeVoegen) {
      if (!bevinding.punt.voorstel) continue;
      kinderen.push(
        new Paragraph({
          children: [
            ...invoegRuns(`${bevinding.punt.titel}. ${bevinding.punt.voorstel}`, revisie),
            ...invoegRuns(motiveringTekst(bevinding), revisie),
          ],
        })
      );
    }
  }

  return new Document({
    creator: auteur,
    title: "Nazicht ontwerpconventie — wijzigingsvoorstellen",
    subject: opties.rapport.akteType,
    styles: woordStijlen("nl"),
    features: { updateFields: true },
    sections: [
      {
        footers: { default: paginavoettekst("nl") },
        children: kinderen,
      },
    ],
  });
}

/**
 * Verpakt het nazichtdocument tot een .docx-buffer mét 'Wijzigingen
 * bijhouden' actief (server-/testpad; de client-pagina gebruikt
 * `Packer.toBlob` + `forceerTrackChangesBlob`).
 */
export async function genereerNazichtWordDocument(opties: NazichtWordOpties): Promise<Buffer> {
  const buffer = await Packer.toBuffer(maakNazichtDocument(opties));
  return forceerTrackChanges(Buffer.from(buffer));
}
