import { useEffect, useRef } from 'react';

import { anzeigegroesseBereinigen, groesser, kleiner } from '../../../shared/ansicht';
import { bridge } from '../bridge';

/**
 * `Strg` und `+`, `-`, `0` – die Anzeigegröße über die Tastatur.
 *
 * ## Warum es diesen Haken gibt
 *
 * `Strg` und `+` taten unter Windows **nichts**. Gemeldet von einem Nutzer mit
 * deutscher Tastatur, nachgemessen und bestätigt: Der Menüeintrag „Größer“
 * wirkt (per Klick springt der Zoomfaktor von 1 auf 1,1), nur die
 * Tastenkombination erreichte ihn nie.
 *
 * Der Grund liegt in der Übersetzung des Menü-Beschleunigers. Electron liest
 * den Namen `Plus` als die **umgeschaltete** Form von `=` und meldet damit
 * faktisch `Strg+Umschalt+=` beim Betriebssystem an – richtig für eine
 * amerikanische Tastatur, auf der das Pluszeichen nur mit Umschalt zu
 * erreichen ist. Auf einer deutschen Tastatur ist `+` eine eigene Taste
 * **ohne** Umschalt; die angemeldete Kombination traf dort nie zu.
 *
 * ## Warum im Renderer und nicht im Hauptprozess
 *
 * Der erste Anlauf fing die Tasten im Hauptprozess über `before-input-event`
 * ab. Nachgemessen liefert dieses Ereignis für Tasten, die ein Prüflauf
 * schickt, **überhaupt nichts** – die Behebung wäre unprüfbar geblieben,
 * genau wie der Beschleuniger selbst. Ein `keydown` am Fenster erreicht
 * dagegen jeder Playwright-Lauf und jeder jsdom-Test.
 *
 * ## Warum keine Layout-Erkennung nötig ist
 *
 * `KeyboardEvent.key` ist das Zeichen, das die Tastatur **tatsächlich
 * geliefert** hat – das Betriebssystem hat das Layout da bereits angewandt.
 * Auf einer deutschen Tastatur kommt `+` an, auf einer amerikanischen `=`
 * oder mit Umschalt `+`, auf dem Ziffernblock `+` mit `code === 'NumpadAdd'`.
 * Alle drei sind hier genannt. Das Layout selbst muss die Anwendung nie
 * kennen, und sie soll es auch nicht: Wer es abfragt, trifft Annahmen, die
 * bei der nächsten Tastatur wieder falsch sind. Genau dieser Fehler steckte
 * im Beschleuniger.
 *
 * ## Warum `metaKey` ausgeschlossen ist
 *
 * Unter macOS lautet die Kombination `Cmd` und `+`; dort meldet Electron den
 * Beschleuniger zuverlässig an, und `registerAccelerator: false` ist
 * wirkungslos. Ohne diesen Ausschluss zoomten beide Wege zusammen doppelt.
 */
export function useZoomtasten(gespeichert: number | undefined): void {
  /* Der jeweils gültige Wert, ohne dass der Haken bei jeder Änderung neu
     eingehängt wird. Ein Ref statt einer Abhängigkeit: Sonst risse jeder
     Zoomschritt den Zuhörer ab und hängte ihn neu ein. */
  const aktuell = useRef(anzeigegroesseBereinigen(gespeichert));

  useEffect(() => {
    aktuell.current = anzeigegroesseBereinigen(gespeichert);
  }, [gespeichert]);

  useEffect(() => {
    const beobachten = bridge()?.anzeigegroesseBeobachten;
    return beobachten?.((neu) => {
      aktuell.current = anzeigegroesseBereinigen(neu);
    });
  }, []);

  useEffect(() => {
    function beiTaste(ereignis: KeyboardEvent): void {
      if (!ereignis.ctrlKey || ereignis.metaKey || ereignis.altKey) {
        return;
      }

      const groesserGewuenscht =
        ereignis.key === '+' || ereignis.key === '=' || ereignis.code === 'NumpadAdd';
      const kleinerGewuenscht =
        ereignis.key === '-' || ereignis.key === '_' || ereignis.code === 'NumpadSubtract';
      const zurueckGewuenscht = ereignis.key === '0' || ereignis.code === 'Numpad0';

      let ziel: number;
      if (groesserGewuenscht) {
        ziel = groesser(aktuell.current);
      } else if (kleinerGewuenscht) {
        ziel = kleiner(aktuell.current);
      } else if (zurueckGewuenscht) {
        ziel = 100;
      } else {
        /* Nur wenn wir wirklich zuständig sind: Sonst schluckte diese Stelle
           jede andere Kombination mit Strg – Kopieren, Einfügen, Neu laden. */
        return;
      }

      ereignis.preventDefault();
      aktuell.current = ziel;
      const setzen = bridge()?.anzeigegroesseSetzen;
      /* Ohne Anwendungskern bleibt die Groesse stehen - sie haengt am Fenster,
         nicht am Dokument, und laesst sich hier nicht selbst aendern. */
      void setzen?.(ziel);
    }

    window.addEventListener('keydown', beiTaste);
    return () => {
      window.removeEventListener('keydown', beiTaste);
    };
  }, []);

  /*
    ── Strg und Mausrad ───────────────────────────────────────────────────

    Der unter Windows verbreitetste Zoomgriff – Browser, Office, Explorer –
    fehlte ausgerechnet in einer Anwendung, deren Anzeigegröße bis 400 Prozent
    ein zentrales Merkmal ist. Electron zoomt bei `Strg` und Mausrad nicht von
    sich aus.

    `{ passive: false }` ist hier nicht optional: `wheel`-Zuhörer am `window`
    sind in Chromium standardmäßig passiv, und `preventDefault()` bliebe dann
    wirkungslos – die Seite rollte zusätzlich zum Zoom.

    Das Trackpad ist mit abgedeckt: Chromium meldet die Kneifgeste ebenfalls
    als `wheel` mit `ctrlKey`.
  */
  useEffect(() => {
    function beiRad(ereignis: WheelEvent): void {
      if (!ereignis.ctrlKey || ereignis.metaKey || ereignis.altKey || ereignis.deltaY === 0) {
        return;
      }

      ereignis.preventDefault();
      /* Nach oben gedreht ist `deltaY` negativ – das ist „größer“. */
      const ziel = ereignis.deltaY < 0 ? groesser(aktuell.current) : kleiner(aktuell.current);
      if (ziel === aktuell.current) {
        return;
      }

      aktuell.current = ziel;
      const setzen = bridge()?.anzeigegroesseSetzen;
      void setzen?.(ziel);
    }

    window.addEventListener('wheel', beiRad, { passive: false });
    return () => {
      window.removeEventListener('wheel', beiRad);
    };
  }, []);
}
