/**
 * Erzeugung von PDF-Dokumenten.
 *
 * **Warum ein eigenes, verstecktes Fenster.** Nur `webContents.printToPDF`
 * kennt die Optionen `generateTaggedPDF` und `generateDocumentOutline`;
 * `webContents.print` und der Weg über `window.print()` können prinzipiell
 * kein getaggtes PDF erzeugen. Ohne Tags hat das Ergebnis keinen
 * Strukturbaum – keine Überschriftenebenen, keine Tabellenzuordnung, keine
 * Sprachangabe. Für eine Anwendung mit diesem Anspruch wäre das kein
 * Ausdruck, sondern ein Bild von Buchstaben.
 *
 * Das Bildschirmfenster zu drucken kam ebenfalls nicht in Frage: Der
 * Startbildschirm ergibt sechs Seiten Bedienoberfläche, die Antwortoptionen
 * stünden in der Reihenfolge der Sitzung – bei eingeschaltetem Mischen also
 * nicht in der des Katalogs –, und das eingestellte Farbschema wäre auf
 * Papier womöglich unlesbar.
 *
 * **Warum eine eigene Sitzung.** Das Druckfenster hat mit dem Lernbetrieb
 * nichts zu tun: keine Bridge, keine Berechtigungen, kein gemeinsamer
 * Speicher. `session.fromPartition` gibt ihm einen eigenen Bereich, damit es
 * nichts erben kann, was es nicht braucht. Seine Richtlinie bringt das
 * Dokument selbst mit (`<meta http-equiv="Content-Security-Policy">` in
 * `shared/druck/dokument.ts`).
 *
 * **Die stille Falle.** Wird der eingebettete Stil aus irgendeinem Grund
 * blockiert, entsteht das PDF trotzdem – nur eben unformatiert, mit
 * Standardschrift und ohne die erzwungene helle Palette. `printToPDF` wirft
 * dabei nicht. Genau deshalb prüft `e2e/druck.spec.ts` nicht nur, dass eine
 * Datei entstanden ist, sondern misst im Druckfenster nach, ob der Stil
 * wirklich greift.
 */

import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { BrowserWindow, session, type BrowserWindow as Fenster } from 'electron';

import { fusszeilenVorlage, KOPFZEILE_LEER, type Quellenangabe } from '../shared/druck/dokument';

/** Eigener Sitzungsbereich des Druckfensters. */
const DRUCK_PARTITION = 'druckfenster';

/**
 * Seitenränder in Zoll.
 *
 * Unten mehr Platz, weil dort die Fußzeile mit der Quellenangabe steht –
 * ohne reservierten Rand schneidet Chromium sie ab.
 */
const RAENDER = Object.freeze({ top: 0.6, bottom: 0.75, left: 0.6, right: 0.6 });

export interface Druckauftrag {
  /** Das vollständige Dokument als HTML. */
  readonly html: string;
  readonly quelle: Quellenangabe;
}

/**
 * Erzeugt aus dem Dokument ein PDF.
 *
 * Das HTML wird in eine temporäre Datei geschrieben und mit `loadFile`
 * geladen. Eine `data:`-URL wäre bequemer, hätte aber einen undurchsichtigen
 * Ursprung und andere Regeln – und sehr lange Dokumente sprengen die
 * Längengrenze von URLs.
 *
 * Das Verzeichnis wird in jedem Fall wieder entfernt, auch wenn das Erzeugen
 * scheitert.
 */
export async function pdfErzeugen(auftrag: Druckauftrag): Promise<Buffer> {
  const ordner = mkdtempSync(join(tmpdir(), 'wsk-druck-'));
  const datei = join(ordner, 'dokument.html');
  let fenster: Fenster | null = null;

  try {
    writeFileSync(datei, auftrag.html, 'utf-8');

    fenster = new BrowserWindow({
      show: false,
      webPreferences: {
        session: session.fromPartition(DRUCK_PARTITION),
        /* Kein Preload, keine Brücke, kein Skript: Das Dokument ist reiner
           Text und soll auch nichts anderes ausführen können. Das Feld
           `preload` fehlt hier bewusst – gesetzt auf `undefined` wäre es
           unter `exactOptionalPropertyTypes` ein Typfehler, und weggelassen
           ist es ohnehin deutlicher. */
        javascript: false,
        contextIsolation: true,
        nodeIntegration: false,
        sandbox: true,
        webSecurity: true,
        spellcheck: false,
      },
    });

    await fenster.loadFile(datei);

    return await fenster.webContents.printToPDF({
      pageSize: 'A4',
      margins: RAENDER,
      printBackground: true,
      displayHeaderFooter: true,
      headerTemplate: KOPFZEILE_LEER,
      footerTemplate: fusszeilenVorlage(auftrag.quelle),
      /* Beide Optionen sind in Electron als experimentell gekennzeichnet und
         sichern PDF/UA ausdrücklich NICHT zu. Gemessen erzeugen sie
         Strukturbaum, Sprachangabe und Lesezeichen – ein großer Gewinn für
         eine kleine Unsicherheit. Was dabei belegt ist und was nicht, steht
         in docs/barrierefreiheit-pruefplan.md. */
      generateTaggedPDF: true,
      generateDocumentOutline: true,
    });
  } finally {
    /* `destroy` statt `close`: Ein verstecktes Fenster hat niemanden, der
       ein „Wirklich schließen?“ beantworten könnte. */
    fenster?.destroy();
    try {
      rmSync(ordner, { recursive: true, force: true });
    } catch {
      /* Ein verwaistes Temp-Verzeichnis darf keinen Export scheitern lassen. */
    }
  }
}
