import { useCallback, useEffect, useState } from 'react';

import { EINSTELLUNGEN_STANDARD } from '../../../shared/ipc';
import {
  farbschemaFuer,
  istThemeAuswahl,
  themeAufloesen,
  umschaltAnsage,
  type ThemeAufgeloest,
  type ThemeAuswahl,
} from '../../../shared/theme';
import { bridge } from '../bridge';
import { useSystemSignale } from './useSystemSignale';

/**
 * Schlüssel des Zwischenspeichers im `localStorage`.
 *
 * ## Warum das Farbschema als einzige Einstellung hier liegt
 *
 * Führende Quelle ist `einstellungen.json` – wie bei jeder anderen
 * Einstellung, und der Schreibweg unten geht ausschließlich dorthin. Der
 * `localStorage` ist ein **Zwischenspeicher**, kein zweiter Ablageort.
 *
 * Er ist nötig, weil das Farbschema anliegen muss, **bevor** das erste Bild
 * steht: `einstellungen:lesen` ist ein asynchroner IPC-Aufruf und antwortet
 * frühestens nach dem ersten Rendern. Ohne sofort verfügbaren Wert zeichnete
 * die Anwendung eine Runde lang das Standardthema und spränge dann um – ein
 * Aufblitzen genau bei denen, die auf ein blendarmes oder kontrastreiches
 * Thema angewiesen sind. Der Hauptprozess deckt dieselbe Lücke von der
 * anderen Seite ab (`fenster.ts`, `startfarbeFuer`), aber nur für die
 * Fensterfarbe; das `data-thema`-Attribut kann nur der Renderer setzen.
 *
 * Damit der Zwischenspeicher nie gegen die Datei steht, gilt eine Regel:
 * **Er wird nur geschrieben, wenn die Datei den Wert hat** – nach dem Lesen
 * und nach erfolgreichem Schreiben. Sonst überlebte ein gescheiterter
 * Schreibversuch als „gültiger“ Startwert und erzeugte beim nächsten Start
 * genau das Aufblitzen, das er verhindern soll.
 */
const SPEICHERSCHLUESSEL = 'waffensachkunde.thema';

/** Sofort verfügbarer Startwert, damit vor der IPC-Antwort nichts umspringt. */
function auswahlAusSpeicher(): ThemeAuswahl {
  try {
    const wert = window.localStorage.getItem(SPEICHERSCHLUESSEL);
    return istThemeAuswahl(wert) ? wert : EINSTELLUNGEN_STANDARD.thema;
  } catch {
    return EINSTELLUNGEN_STANDARD.thema;
  }
}

/** Legt den bestätigten Stand in den Zwischenspeicher. */
function zwischenspeichern(auswahl: ThemeAuswahl): void {
  try {
    window.localStorage.setItem(SPEICHERSCHLUESSEL, auswahl);
  } catch {
    /* Ohne localStorage entfällt nur der schnelle Startwert; die Einstellung
       selbst liegt in der Datei und geht nicht verloren. */
  }
}

export interface ThemaSteuerung {
  /** Was eingestellt ist – inklusive `system`. */
  readonly auswahl: ThemeAuswahl;
  /** Was tatsächlich dargestellt wird. */
  readonly aufgeloest: ThemeAufgeloest;
  /** Text für die `aria-live`-Region; leer bis zur ersten Umschaltung. */
  readonly ansage: string;
  readonly auswahlSetzen: (auswahl: ThemeAuswahl) => void;
}

/**
 * Verwaltet die Theme-Auswahl:
 *  - liest den zuletzt gespeicherten Wert (localStorage sofort, IPC nachgelagert),
 *  - löst ihn gegen die Systemsignale auf,
 *  - schreibt das Ergebnis nach `<html data-thema="…">`,
 *  - formuliert die Ansage für Screenreader.
 */
export function useThema(): ThemaSteuerung {
  const signale = useSystemSignale();
  const [auswahl, setzeAuswahl] = useState<ThemeAuswahl>(auswahlAusSpeicher);
  const [ansage, setzeAnsage] = useState('');

  const aufgeloest = themeAufloesen(auswahl, signale);

  // Gespeicherte Einstellung aus dem Main-Prozess nachladen.
  useEffect(() => {
    let abgebrochen = false;

    void bridge()
      ?.einstellungenLesen()
      .then((einstellungen) => {
        if (!abgebrochen && istThemeAuswahl(einstellungen.thema)) {
          setzeAuswahl(einstellungen.thema);
          /* Der Zwischenspeicher folgt der Datei – auch dann, wenn sie von
             woanders kommt (übernommenes Benutzerverzeichnis, von Hand
             bearbeitet). Ohne diesen Abgleich zeigte der nächste Start
             zuerst den alten Wert und spränge dann um. */
          zwischenspeichern(einstellungen.thema);
        }
      })
      .catch((fehler: unknown) => {
        console.warn('[thema] Einstellungen konnten nicht gelesen werden:', fehler);
      });

    return () => {
      abgebrochen = true;
    };
  }, []);

  // Aufgelöstes Theme auf das Wurzelelement anwenden.
  useEffect(() => {
    const wurzel = document.documentElement;
    wurzel.dataset['thema'] = aufgeloest;
    /* Mit den Signalen: Beim Windows-Kontrastdesign sagt `hochkontrast` nur,
       dass die Farben von aussen kommen – ob hell oder dunkel, weiß allein
       das System. */
    wurzel.style.colorScheme = farbschemaFuer(aufgeloest, signale);
  }, [aufgeloest, signale]);

  const auswahlSetzen = useCallback(
    (neue: ThemeAuswahl) => {
      setzeAuswahl(neue);
      setzeAnsage(umschaltAnsage(neue, themeAufloesen(neue, signale), signale));

      const schreiben = bridge()?.einstellungenSchreiben;
      if (!schreiben) {
        /* Ohne Anwendungskern gibt es keine Datei, die führen könnte – dann
           ist der Zwischenspeicher alles, was bleibt. */
        zwischenspeichern(neue);
        return;
      }

      /* Die Umstellung greift sofort; nur das dauerhafte Sichern kann
         scheitern (voller Datenträger, schreibgeschütztes Verzeichnis). Dann
         wäre die Einstellung nach dem Neustart wieder weg – das muss gesagt
         werden, und zwar dort, wo die Umschaltung ohnehin angesagt wird. */
      void schreiben({ thema: neue })
        .then(() => {
          /* Erst jetzt in den Zwischenspeicher: Er soll den Stand der Datei
             abbilden und ihm nicht vorauseilen. */
          zwischenspeichern(neue);
        })
        .catch((fehler: unknown) => {
          console.warn('[thema] Einstellungen konnten nicht gespeichert werden:', fehler);
          setzeAnsage(
            `${umschaltAnsage(neue, themeAufloesen(neue, signale), signale)} ` +
              'Diese Wahl konnte nicht dauerhaft gespeichert werden und gilt nur für diese Sitzung.',
          );
        });
    },
    [signale],
  );

  return { auswahl, aufgeloest, ansage, auswahlSetzen };
}
