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

import type { OffenerLauf } from '../../../shared/pruefung';
import { lernBruecke } from '../lernen/bruecke';

export interface OffenePruefung {
  /** Der unterbrochene Lauf, oder `null` – auch solange geladen wird. */
  readonly lauf: OffenerLauf | null;
  readonly laedt: boolean;
  /** Verwirft den Lauf im Anwendungskern und vergisst ihn hier. */
  readonly verwerfen: () => Promise<void>;
  /** Vergisst ihn nur hier – etwa, weil er gerade fortgesetzt wird. */
  readonly vergessen: () => void;
  readonly neuLaden: () => void;
}

/**
 * Der unterbrochene Prüfungsbogen eines Profils.
 *
 * **Warum das ein eigener Hook ist.** Der Lernstand-Hook lädt Übersicht und
 * Profile; ein Bogen hat damit nichts zu tun und würde bei jedem Neuladen des
 * Lernstands mitgezogen. Umgekehrt muss dieser Hook auf Dinge hören, die den
 * Lernstand nicht berühren – etwa das Zurücksetzen, das den offenen Bogen
 * mitnimmt.
 *
 * Fehlt der Kanal oder das Profil, gibt es schlicht nichts fortzusetzen. Das
 * ist kein Fehler und wird nicht gemeldet: Ohne Anwendungskern wurde auch
 * nichts gesichert.
 */
export function useOffenePruefung(profilId: number | null): OffenePruefung {
  /*
    Das Ergebnis trägt die Profil-Kennung mit, zu der es gehört.

    Sonst bräuchte ein Profilwechsel ein Zurücksetzen im Effekt – und ein
    Augenblick, in dem der Bogen des einen Profils unter dem anderen steht,
    wäre genau die Art Fehler, die niemand bemerkt.
  */
  const [geladen, setzeGeladen] = useState<{
    readonly profilId: number;
    readonly lauf: OffenerLauf | null;
  } | null>(null);
  const [runde, setzeRunde] = useState(0);

  const lauf = geladen !== null && geladen.profilId === profilId ? geladen.lauf : null;
  /* Abgeleitet statt gesetzt: Ein eigener Zustand dafür wäre eine zweite
     Wahrheit über denselben Sachverhalt – und ein Setzen im Effekt. */
  const laedt = profilId !== null && geladen?.profilId !== profilId;

  useEffect(() => {
    const lesen = lernBruecke()?.pruefungOffen;
    if (!lesen || profilId === null) {
      return undefined;
    }

    let abgebrochen = false;

    void lesen(profilId)
      .then((gefunden) => {
        if (!abgebrochen) {
          setzeGeladen({ profilId, lauf: gefunden });
        }
      })
      .catch((fehler: unknown) => {
        console.warn('[pruefung] Offener Lauf konnte nicht gelesen werden:', fehler);
        if (!abgebrochen) {
          setzeGeladen({ profilId, lauf: null });
        }
      });

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

  const vergessen = useCallback(() => {
    setzeGeladen(profilId === null ? null : { profilId, lauf: null });
  }, [profilId]);

  const verwerfen = useCallback(async () => {
    const kanal = lernBruecke()?.pruefungVerwerfen;
    if (kanal && profilId !== null) {
      await kanal(profilId);
    }
    setzeGeladen(profilId === null ? null : { profilId, lauf: null });
  }, [profilId]);

  const neuLaden = useCallback(() => {
    setzeRunde((bisher) => bisher + 1);
  }, []);

  return { lauf, laedt, verwerfen, vergessen, neuLaden };
}
