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

import type { Schriftgroesse } from '../../../../shared/druck/stil';
import { bridge } from '../../bridge';
import { fehlerMeldung, kanalFehltMeldung } from '../../lernen/bruecke';
import { Dateiknoepfe } from './Dateiknoepfe';
import { Schriftwahl } from './Fragendruckausgabe';
import { Hinweis } from './Hinweis';

type Zustand =
  | { readonly art: 'bereit' }
  | { readonly art: 'laeuft' }
  | { readonly art: 'fertig'; readonly meldung: string; readonly kennung: string | undefined }
  | { readonly art: 'abgebrochen' }
  | { readonly art: 'fehler'; readonly meldung: string };

export interface LernberichtausgabeProps {
  readonly profilId: number | null;
}

/**
 * Lernbericht als PDF speichern.
 *
 * **Warum die Schaltfläche nicht abgeschaltet wird, während der Bericht
 * entsteht.** Ein `disabled`-Element verliert den Fokus, und der fällt dann
 * auf `<body>` – wer per Tastatur bedient, steht plötzlich am Seitenanfang.
 * Stattdessen bleibt sie erreichbar und meldet sich über `aria-disabled` als
 * gerade nicht verfügbar; der zweite Klick läuft ins Leere.
 *
 * **Warum die Rückmeldung zweimal dasteht.** Eine `aria-live`-Region ist für
 * sehende Nutzende unsichtbar. Ein Vorgang, der eine Datei auf die Platte
 * schreibt, muss aber für alle sichtbar quittiert werden – deshalb steht die
 * Meldung als normaler Text da und wird über `role="status"` zusätzlich
 * angesagt.
 */
export function Lernberichtausgabe({ profilId }: LernberichtausgabeProps): React.JSX.Element {
  const [zustand, setzeZustand] = useState<Zustand>({ art: 'bereit' });
  const [groesse, setzeGroesse] = useState<Schriftgroesse>('normal');
  const laeuftRef = useRef(false);

  const speichern = useCallback(() => {
    if (laeuftRef.current) {
      return;
    }

    const drucken = bridge()?.lernberichtDrucken;
    if (!drucken || profilId === null) {
      setzeZustand({
        art: 'fehler',
        meldung: !drucken
          ? kanalFehltMeldung('druck:lernbericht', 'Der Bericht kann nicht erzeugt werden.')
          : 'Ohne Lernprofil gibt es keinen Bericht – legen Sie zuerst ein Profil an.',
      });
      return;
    }

    laeuftRef.current = true;
    setzeZustand({ art: 'laeuft' });

    void drucken(profilId, groesse)
      .then((ergebnis) => {
        setzeZustand(
          ergebnis.gespeichert && ergebnis.pfad !== null
            ? {
                art: 'fertig',
                meldung: `Der Lernbericht wurde gespeichert: ${ergebnis.pfad}`,
                kennung: ergebnis.dateiKennung,
              }
            : { art: 'abgebrochen' },
        );
      })
      .catch((fehler: unknown) => {
        setzeZustand({
          art: 'fehler',
          meldung: fehlerMeldung(fehler, 'Der Lernbericht konnte nicht gespeichert werden.'),
        });
      })
      .finally(() => {
        laeuftRef.current = false;
      });
  }, [groesse, profilId]);

  const laeuft = zustand.art === 'laeuft';

  return (
    <div className="bericht">
      <p>
        Ihr Stand als PDF: Gesamtübersicht, die Zahlen je Kapitel, das Tagespensum und die
        abgeschlossenen Prüfungssimulationen. Fragen und Antworten stehen nicht darin.
      </p>

      {/*
        Die Wahl steckt seit 0.18.0 in einem eigenen Baustein. Hier stand
        vorher ein fest verdrahtetes `name="berichtSchrift"` – mit drei
        Ausgabeblöcken auf demselben Bildschirm hätten alle drei dieselbe
        Radiogruppe gebildet, und Großdruck im Fehlerprotokoll stellte den
        Lernbericht mit um. Seit 0.20.0 zeigt der Startbildschirm ohnehin nur
        einen Block zur Zeit (`Druckkarte.tsx`).
      */}
      <Schriftwahl wert={groesse} onWert={setzeGroesse} />

      <div>
        <button type="button" className="knopf" aria-disabled={laeuft} onClick={speichern}>
          {laeuft ? 'Der Bericht wird erzeugt …' : 'Lernbericht als PDF speichern'}
        </button>
      </div>

      {/* Sichtbar für alle, angesagt für Screenreader – dieselbe Meldung. */}
      <div role="status" aria-live="polite" className="bericht__meldung">
        {zustand.art === 'fertig' ? <Hinweis art="hinweis">{zustand.meldung}</Hinweis> : null}
        {zustand.art === 'abgebrochen' ? (
          <Hinweis art="hinweis">Es wurde nichts gespeichert.</Hinweis>
        ) : null}
        {zustand.art === 'fehler' ? <Hinweis art="fehler">{zustand.meldung}</Hinweis> : null}
      </div>

      {/* Außerhalb der Live-Region: Zwei Schaltflächen sind nichts, was
          vorgelesen werden müsste, sobald sie erscheinen – sie stehen einfach
          da, wo man sie als Nächstes braucht. */}
      {zustand.art === 'fertig' ? <Dateiknoepfe kennung={zustand.kennung} /> : null}
    </div>
  );
}
