// @vitest-environment node
/**
 * Der Wächter über die laufende Prüfung.
 *
 * Er entscheidet, ob das Fenster beim Schließen nachfragt. Bis Fassung 0.24.1
 * hatte er **keinen einzigen Test** – weder hier noch in Playwright –, obwohl
 * an ihm zwei gegenläufige Fehler hängen: Vergisst er zu früh, geht ein
 * Prüfungsbogen ohne Rückfrage verloren; vergisst er zu spät, hängt das
 * Fenster für immer an einer Frage zu einer Prüfung, die es nicht mehr gibt.
 *
 * Geprüft wird gegen Attrappen von `WebContents` und `BrowserWindow`: Der
 * Wächter benutzt von beiden nur `id` und `isDestroyed()`, und ein echtes
 * Electron-Fenster für diese Rechnung zu starten wäre teuer ohne Gewinn.
 */

import { beforeEach, describe, expect, it } from 'vitest';

import type { BrowserWindow, WebContents } from 'electron';

import {
  laeuftPruefung,
  laufMelden,
  laufVergessen,
  laufwaechterLeeren,
} from '../src/main/laufwaechter';

/** Nur die beiden Felder, die der Wächter anfasst. */
function inhalt(id: number, zerstoert = false): WebContents {
  return { id, isDestroyed: () => zerstoert } as unknown as WebContents;
}

function fenster(webContents: WebContents): BrowserWindow {
  return { webContents } as unknown as BrowserWindow;
}

beforeEach(() => {
  laufwaechterLeeren();
});

describe('Laufwächter', () => {
  it('meldet ohne jede Meldung keine laufende Prüfung', () => {
    expect(laeuftPruefung(fenster(inhalt(1)))).toBe(false);
  });

  it('merkt sich eine laufende Prüfung', () => {
    const eins = inhalt(1);
    laufMelden(eins, true);

    expect(laeuftPruefung(fenster(eins))).toBe(true);
  });

  /*
    Der Renderer schickt seinen Zustand auch beim Aufbau – also `false` nach
    einem Neuladen. Ein Wächter, der nur Kanten meldete, bliebe hängen.
  */
  it('nimmt den Merker auf eine Meldung „läuft nicht“ zurück', () => {
    const eins = inhalt(1);
    laufMelden(eins, true);
    laufMelden(eins, false);

    expect(laeuftPruefung(fenster(eins))).toBe(false);
  });

  it('verträgt dieselbe Meldung mehrfach', () => {
    const eins = inhalt(1);
    laufMelden(eins, true);
    laufMelden(eins, true);
    laufMelden(eins, false);

    expect(laeuftPruefung(fenster(eins))).toBe(false);
  });

  it('hält die Fenster auseinander', () => {
    /* Zwei Fenster sind erreichbar – die Hilfe ist zwar ein Dialog, aber ein
       zweiter Programmstart legt ein eigenes an. Der Merker des einen darf
       das andere nicht betreffen. */
    const eins = inhalt(1);
    const zwei = inhalt(2);
    laufMelden(eins, true);

    expect(laeuftPruefung(fenster(eins))).toBe(true);
    expect(laeuftPruefung(fenster(zwei))).toBe(false);
  });

  it('vergisst den Merker bei neuem Dokument oder Absturz', () => {
    const eins = inhalt(1);
    laufMelden(eins, true);
    laufVergessen(eins);

    expect(laeuftPruefung(fenster(eins))).toBe(false);
  });

  /*
    Die zweite, unabhängige Sperre: Ein zerstörtes `webContents` liefert
    niemals „es läuft eine Prüfung“. Ohne sie könnte ein abgestürzter Renderer
    das Fenster unschließbar machen – und der Nutzer säße vor einem Fenster,
    das weder arbeitet noch zugeht.
  */
  it('meldet für ein zerstörtes Fenster nie eine laufende Prüfung', () => {
    const eins = inhalt(1);
    laufMelden(eins, true);

    expect(laeuftPruefung(fenster(inhalt(1, true)))).toBe(false);
  });

  it('räumt mit „leeren“ alles weg', () => {
    laufMelden(inhalt(1), true);
    laufMelden(inhalt(2), true);

    laufwaechterLeeren();

    expect(laeuftPruefung(fenster(inhalt(1)))).toBe(false);
    expect(laeuftPruefung(fenster(inhalt(2)))).toBe(false);
  });
});
