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

import { richtigeLabels } from '../../../../shared/katalog';
import { BEWERTUNG_BEZEICHNUNG } from '../../../../shared/lernstand';
import type { KatalogIndex } from '../../hooks/useKatalog';
import { useSitzung } from '../../hooks/useSitzung';
import { useTastenkuerzel } from '../../hooks/useTastenkuerzel';
import { SPRECHTEMPO_STANDARD } from '../../../../shared/sprechtempo';
import { useVorlesen, type Sprachausgabe } from '../../hooks/useVorlesen';
import { Fehlermeldeblock } from './Fehlermeldeblock';
import {
  ERGEBNIS_SYMBOL,
  ERGEBNIS_TITEL,
  giltAlsRichtig,
  istAuswahlfrage,
  labelListe,
  loesungssatz,
  type ErgebnisArt,
} from '../../lernen/bewertung';
import { useErklaerungen } from '../../hooks/useErklaerungen';
import { useGlossar } from '../../hooks/useGlossar';
import { ergebnisVorlesen, frageVorlesen } from '../../lernen/vorlesetexte';
import type { SitzungsBilanz, Sitzungsauftrag } from '../../lernen/typen';
import { AuswahlAntwort } from './AuswahlAntwort';
import { BegriffeZurFrage } from './BegriffeZurFrage';
import { Erklaerungstafel } from './Erklaerungstafel';
import { Fragesteckbrief } from './Fragesteckbrief';
import { Ergebnisbereich } from './Ergebnisbereich';
import { Fortschritt } from './Fortschritt';
import { FrageKopf } from './FrageKopf';
import { FreitextAntwort } from './FreitextAntwort';
import { Hinweis } from './Hinweis';
import { LetzteAntwort } from './LetzteAntwort';
import { Musterantwort } from './Musterantwort';
import { Selbstbewertung } from './Selbstbewertung';
import { VerwandteFragen } from './VerwandteFragen';
import { Vorlesetaste } from './Vorlesetaste';

export interface LernsitzungProps {
  readonly auftrag: Sitzungsauftrag;
  readonly katalogIndex: KatalogIndex;
  readonly profilId: number | null;
  readonly kuerzelAktiv: boolean;
  /** Sprachausgabe eingeschaltet (Einstellung „Vorlesen“). */
  readonly vorlesenAktiv: boolean;
  /** Ohne Knopfdruck vorlesen. Nur sinnvoll, wenn {@link vorlesenAktiv}. */
  readonly vorlesenAutomatisch: boolean;
  /** Bei falscher Antwort die ausführliche Begründung vorlesen. */
  readonly vorlesenErklaerung: boolean;
  /** Sprechgeschwindigkeit; Stufen in `shared/sprechtempo.ts`. */
  readonly sprechtempo?: number;
  /**
   * Verschweigen, wie viele Antworten richtig sind (Einstellung unter
   * „Schwierigkeit“). Die Prüfungssimulation hält es ohnehin so.
   */
  readonly antwortzahlVerbergen?: boolean;
  readonly einstiegRef: React.RefObject<HTMLHeadingElement | null>;
  readonly onBeenden: (bilanz: SitzungsBilanz) => void;
  readonly onZumStart: () => void;
}

/**
 * Das Herzstück: eine Frage nach der anderen, ohne Zeitdruck.
 *
 * Weitergeschaltet wird ausschließlich auf ausdrückliche Eingabe (WCAG 3.2.2),
 * das Ergebnis geht über eine Live-Region heraus und der Fokus wandert
 * anschließend auf den Ergebnisbereich.
 */
export function Lernsitzung({
  auftrag,
  katalogIndex,
  profilId,
  kuerzelAktiv,
  vorlesenAktiv,
  vorlesenAutomatisch,
  vorlesenErklaerung,
  sprechtempo = SPRECHTEMPO_STANDARD,
  antwortzahlVerbergen = false,
  einstiegRef,
  onBeenden,
  onZumStart,
}: LernsitzungProps): React.JSX.Element {
  /* Eine Entscheidung, zwei Empfänger: Sie bestimmt die Bauart der
     Bedienelemente (Kästchen statt Radios) UND die Auswahllogik. Ginge sie
     nur an die Darstellung, widerspräche sich die Frage selbst – siehe den
     Kommentar an `umschalten` in useSitzung. */
  const anzahlVerraten = !antwortzahlVerbergen;
  const sitzung = useSitzung(auftrag, katalogIndex, profilId, onBeenden, anzahlVerraten);
  const glossar = useGlossar();
  const erklaerungen = useErklaerungen();
  const stimme = useVorlesen(
    vorlesenAktiv,
    `${String(sitzung.nummer)}:${sitzung.schritt}`,
    sprechtempo,
  );
  const { schritt, bestaetigen, weiter } = sitzung;

  const aufEingabe = useCallback(() => {
    if (schritt === 'antworten') {
      bestaetigen();
      return;
    }
    if (schritt === 'ergebnis') {
      weiter();
    }
    /* Im Schritt „selbstbewertung“ bewusst nichts: Die Stufe muss gewählt
       werden, sie lässt sich nicht versehentlich überspringen. */
  }, [bestaetigen, schritt, weiter]);

  useTastenkuerzel({
    aktiv: kuerzelAktiv && sitzung.ladezustand === 'bereit',
    aufZiffer: sitzung.optionAnPosition,
    aufEingabe,
    aufMerken: sitzung.merkenUmschalten,
  });

  /*
    Jede neue Frage holt den Fokus auf ihre Überschrift – auch die erste,
    sobald die Sitzung geladen ist. Ohne diesen Sprung bliebe der Fokus an
    der Schaltfläche hängen, die es nach dem Weiterblättern nicht mehr gibt.
  */
  const { ladezustand, nummer } = sitzung;
  useEffect(() => {
    if (ladezustand === 'bereit') {
      einstiegRef.current?.focus();
    }
  }, [einstiegRef, ladezustand, nummer]);

  /*
    Was gesprochen würde – abhängig davon, wie weit die Frage bearbeitet
    ist. Steht hier oben, weil Hooks vor den frühen Rückgaben liegen müssen
    und die Ansage sonst je nach Ladezustand aus- und wieder eingehängt
    würde.
  */
  const gesprochenerText = ((): string | null => {
    const stand = sitzung.aktuelle;
    if (stand === null) {
      return null;
    }
    if (schritt === 'antworten') {
      return frageVorlesen(stand.frage, stand.optionen);
    }

    const erklaerung = erklaerungen.zu(stand.frage.id);
    const saetze: string[] = [];
    let titel = 'Ergebnis';

    if (sitzung.ergebnis !== null) {
      titel = ERGEBNIS_TITEL[sitzung.ergebnis.art];
      saetze.push(loesungssatz(richtigeLabels(stand.frage)));
      if (sitzung.ergebnis.fehlend.length > 0) {
        saetze.push(`Nicht gewählt hatten Sie: ${labelListe(sitzung.ergebnis.fehlend)}.`);
      }
      if (sitzung.ergebnis.zuviel.length > 0) {
        saetze.push(`Falsch gewählt hatten Sie: ${labelListe(sitzung.ergebnis.zuviel)}.`);
      }
    } else if (sitzung.bewertung !== null) {
      titel = BEWERTUNG_BEZEICHNUNG[sitzung.bewertung];
    }

    return ergebnisVorlesen({
      titel,
      saetze,
      musterantwort: stand.frage.musterantwort?.text,
      erklaerung: erklaerung?.kurz,
    });
  })();

  /*
    Von selbst vorlesen – aber nur, wer es bestellt hat.

    Bis Fassung 0.11.1 begann diese Ansage, sobald die Sprachausgabe
    eingeschaltet war. Gemeldet von einem Nutzer, und die eigenen Texte gaben
    ihm recht: Schalter wie Handbuch sagten eine *Schaltfläche* zu, von
    selbstständigem Sprechen stand in keinem etwas. Wer einen Knopf wollte,
    bekam ungefragt eine Stimme dazu.

    Abgeschafft ist sie deshalb trotzdem nicht: Für jemanden mit
    Lese-Rechtschreib-Störung oder ermüdeten Augen ist ein Knopfdruck je Frage
    genau die Hürde, die diese Funktion abbauen soll. Sie hat jetzt einen
    eigenen Schalter und steht ab Werk aus.

    Gesprochen wird beides – die neue Frage, sobald sie erscheint, und die
    Rückmeldung nach dem Bestätigen. Die Marke verhindert, dass ein beliebiges
    erneutes Rendern dieselbe Stelle noch einmal spricht; gesprochen wird
    genau einmal je Frage und Schritt.
  */
  /*
    Ob diese Frage danebenging – für die ausführliche Begründung.

    Beide Fragetypen: Bei Auswahlfragen zählt alles außer „richtig“, also auch
    die unvollständige Antwort. Bei offenen Fragen ist es die Selbstbewertung
    „Nicht gewusst“; das ist dieselbe Grenze, die `giltAlsRichtig` zieht, und
    dieselbe, nach der FSRS die Frage wieder vorlegt.
  */
  const danebengegangen =
    sitzung.ergebnis !== null
      ? sitzung.ergebnis.art !== 'richtig'
      : sitzung.bewertung === 'nochmal';

  /*
    Was von selbst gesprochen wird – getrennt von dem, was die Schaltfläche
    spricht. Beide Schalter stehen für sich:

      „Frage und Rückmeldung von selbst vorlesen“ – die neue Frage, sobald sie
      erscheint, und nach dem Bestätigen die Rückmeldung samt Kurzfassung der
      Erklärung. Das ist genau das, was auch die Schaltfläche liest.

      „Bei falscher Antwort die ausführliche Begründung“ – nur der lange Text,
      und nur, wenn es danebenging. Er steht in keiner der anderen Ansagen und
      auch nicht auf der Schaltfläche: gesprochen dauert er über eine Minute.

    Sind beide an und ging es daneben, folgt die Begründung auf die
    Rückmeldung – ein Text, den die Sprachausgabe ohnehin in Stücke zerlegt.
  */
  const selbsttaetigerText = ((): string | null => {
    if (gesprochenerText === null) {
      return null;
    }
    const langeErklaerung =
      vorlesenErklaerung && schritt !== 'antworten' && danebengegangen
        ? (erklaerungen.zu(sitzung.aktuelle?.frage.id ?? '')?.text ?? null)
        : null;

    if (vorlesenAutomatisch) {
      return langeErklaerung === null
        ? gesprochenerText
        : `${gesprochenerText}
${langeErklaerung}`;
    }
    return langeErklaerung;
  })();

  /*
    Bis Fassung 0.11.1 begann diese Ansage, sobald die Sprachausgabe
    eingeschaltet war. Gemeldet von einem Nutzer, und die eigenen Texte gaben
    ihm recht: Schalter wie Handbuch sagten eine *Schaltfläche* zu, von
    selbstständigem Sprechen stand in keinem etwas. Wer einen Knopf wollte,
    bekam ungefragt eine Stimme dazu.

    Abgeschafft ist sie deshalb nicht: Für jemanden mit
    Lese-Rechtschreib-Störung oder ermüdeten Augen ist ein Knopfdruck je Frage
    genau die Hürde, die diese Funktion abbauen soll. Sie hat jetzt einen
    eigenen Schalter und steht ab Werk aus.

    Die Marke verhindert, dass ein beliebiges erneutes Rendern dieselbe Stelle
    noch einmal spricht; gesprochen wird genau einmal je Frage und Schritt.
  */
  const zuletztGesprochen = useRef('');
  const { sprich } = stimme;
  useEffect(() => {
    if (!vorlesenAktiv || selbsttaetigerText === null) {
      return;
    }
    const marke = `${String(nummer)}:${schritt}`;
    if (zuletztGesprochen.current === marke) {
      return;
    }
    zuletztGesprochen.current = marke;
    sprich(selbsttaetigerText);
  }, [vorlesenAktiv, selbsttaetigerText, nummer, schritt, sprich]);

  /* `h1` und nicht `h2`: Der Startbildschirm gibt seinen Seitenkopf ab,
     sobald eine Ansicht ihn übernimmt – jede Ansicht führt hier ihre eigene
     `h1`. In der bestückten Sitzung tut das `FrageKopf` mit `ebene = 1`; in
     diesen beiden frühen Rückgaben gibt es keine Frage, und bis Fassung
     0.24.1 begann die Ansicht deshalb auf Ebene 2. Eine zweite `h1` kann
     hier nicht entstehen: `FrageKopf` wird in demselben Zweig nicht
     gerendert. */
  if (sitzung.ladezustand === 'laedt') {
    return (
      <section className="sitzung" aria-label="Lernsitzung">
        <h1 ref={einstiegRef} tabIndex={-1}>
          {auftrag.titel}
        </h1>
        <p>Die Lernsitzung wird vorbereitet …</p>
      </section>
    );
  }

  const { aktuelle } = sitzung;

  if (aktuelle === null) {
    return (
      <section className="sitzung" aria-label="Lernsitzung">
        <h1 ref={einstiegRef} tabIndex={-1}>
          {auftrag.titel}
        </h1>
        <Hinweis art={sitzung.ladezustand === 'fehler' ? 'fehler' : 'hinweis'}>
          {sitzung.meldung ?? 'Diese Lernsitzung enthält keine Fragen.'}
        </Hinweis>
        <button type="button" className="knopf knopf--haupt" onClick={onZumStart}>
          Zum Start
        </button>
      </section>
    );
  }

  const { frage } = aktuelle;
  const auswahlfrage = istAuswahlfrage(frage);
  const gesperrt = schritt !== 'antworten';

  /* Gesucht wird im Fragetext samt Antwortmöglichkeiten und Musterantwort:
     Ein Fachwort, das erst in einer Antwortmöglichkeit auftaucht, blockiert
     das Verständnis genauso. */
  const begriffe = glossar.suche.imText(
    [
      frage.frage.text,
      frage.musterantwort?.text ?? '',
      ...(frage.optionen ?? []).map((option) => option.inhalt.text),
    ].join(' '),
  );

  return (
    <section className="sitzung" aria-label={`Lernsitzung: ${auftrag.titel}`}>
      {/* Sitzungsname und Fortschritt teilen sich eine Zeile – zwei
          getrennte Blöcke kosteten 71 Pixel für sieben Wörter. */}
      <Fortschritt
        beschriftung="Fortschritt der Lernsitzung"
        vorspann={auftrag.titel}
        text={`Frage ${String(sitzung.nummer)} von ${String(sitzung.gesamt)}`}
        wert={sitzung.nummer}
        minimum={0}
        maximum={sitzung.gesamt}
      />

      {sitzung.hinweis !== null ? <Hinweis art="hinweis">{sitzung.hinweis}</Hinweis> : null}
      {sitzung.speicherHinweis !== null ? (
        <Hinweis art="fehler" alsMeldung>
          {sitzung.speicherHinweis}
        </Hinweis>
      ) : null}

      <FrageKopf
        frage={frage}
        kapitelTitel={katalogIndex.bereichTitel(frage.kapitel)}
        abschnittTitel={
          frage.abschnitt === null ? null : katalogIndex.bereichTitel(frage.abschnitt)
        }
        titelRef={einstiegRef}
        bildDaten={katalogIndex.bild}
        beantwortet={schritt !== 'antworten'}
      />

      {auswahlfrage ? (
        <AuswahlAntwort
          optionen={aktuelle.optionen}
          auswahl={sitzung.auswahl}
          mehrfach={aktuelle.mehrfach}
          gesperrt={gesperrt}
          zeigeLoesung={schritt === 'ergebnis'}
          anzahlVerraten={anzahlVerraten}
          kuerzelAktiv={kuerzelAktiv}
          onUmschalten={sitzung.optionWaehlen}
          bildDaten={katalogIndex.bild}
        />
      ) : (
        <FreitextAntwort
          text={sitzung.freitext}
          gesperrt={gesperrt}
          onText={sitzung.freitextSetzen}
        />
      )}

      {/*
        Hinter den Antwortmöglichkeiten, nicht davor.

        Zuerst stand der Aufklapper unmittelbar unter der Frage – mit der
        Überlegung, dass ein unbekanntes Wort genau dort das Verständnis
        blockiert. In der Anwendung erwies sich das als Störung: „Dieser
        Punkt senkt meinen Fokus auf die Antwortmöglichkeiten.“ Der Blick
        soll von der Frage ohne Umweg zu den Antworten laufen.

        Wer ein Wort nicht kennt, findet die Erklärung einen Blick weiter
        unten – und hat vorher immerhin selbst überlegt.
      */}
      <BegriffeZurFrage eintraege={begriffe} beantwortet={schritt !== 'antworten'} />

      {/*
        Die eigene frühere Antwort steht zwischen der eigenen Eingabe und der
        Musterantwort – genau dort, wo verglichen wird. Vor dem Bestätigen
        wäre sie eine Vorlage zum Abschreiben.
      */}
      {!auswahlfrage && schritt !== 'antworten' && aktuelle.letzterFreitext !== undefined ? (
        <LetzteAntwort letzterFreitext={aktuelle.letzterFreitext} />
      ) : null}

      {!auswahlfrage && schritt !== 'antworten' ? (
        /* Die Prueflliste steht bei der Musterantwort und nicht bei der
           Erklaerung: Bewertet wird hier, und ein Massstab hilft nur dort,
           wo die Entscheidung faellt. */
        <Musterantwort
          musterantwort={frage.musterantwort}
          kernpunkte={erklaerungen.zu(frage.id)?.kernpunkte}
        />
      ) : null}

      {schritt === 'selbstbewertung' ? (
        <Selbstbewertung onBewerten={sitzung.selbstBewerten} />
      ) : null}

      {schritt === 'ergebnis' ? (
        <SitzungsErgebnis
          sitzung={sitzung}
          profilId={profilId}
          katalogIndex={katalogIndex}
          {...(vorlesenAktiv && stimme.moeglich ? { stimme } : {})}
        />
      ) : null}

      <div className="sitzung__aktionen">
        {schritt === 'antworten' ? (
          <button type="button" className="knopf knopf--haupt" onClick={bestaetigen}>
            {auswahlfrage ? 'Antwort bestätigen' : 'Musterantwort anzeigen'}
          </button>
        ) : null}

        {schritt === 'ergebnis' ? (
          <button type="button" className="knopf knopf--haupt" onClick={weiter}>
            {sitzung.letzte ? 'Sitzung auswerten' : 'Nächste Frage'}
          </button>
        ) : null}

        {/*
          Die Selbstbewertung zurücknehmen.

          Nur bei offenen Fragen und nur, solange nicht weitergeblättert
          wurde. Ein Fehlgriff auf „Gut" statt „Nochmal" schrieb bis 0.22.0
          sofort und endgültig eine falsche Wiedervorlage – bei vier eng
          beieinanderliegenden Knöpfen kein Randfall. Bei Auswahlfragen steht
          der Knopf nicht: Dort ist die Lösung sichtbar, und eine änderbare
          Antwort wäre ein zweiter Versuch, keine Korrektur.
        */}
        {sitzung.bewertungAenderbar ? (
          <button type="button" className="knopf knopf--leise" onClick={sitzung.bewertungAendern}>
            Bewertung ändern
          </button>
        ) : null}

        {/*
          Die Selbsteinschätzung nach einer richtigen Auswahlantwort.

          Bei Auswahlfragen vergibt die Anwendung für jede richtige Antwort
          ausnahmslos „Gewusst“ – auch für die geratene. Die Entscheidungsnotiz
          zur Ratewahrscheinlichkeit lehnt zwei **automatische** Milderungen
          ab und benennt die Ursache wörtlich: „Das Problem sitzt im Eingang
          (ein Klick ist keine Selbsteinschätzung), nicht in den Parametern.“
          Dieser Knopf öffnet genau diesen Eingang – freiwillig, unaufdringlich
          und ohne dass sich für den, der ihn übersieht, irgendetwas ändert.
        */}
        {sitzung.alsGeratenMoeglich ? (
          <button type="button" className="knopf knopf--leise" onClick={sitzung.alsGeratenWerten}>
            Ich hatte geraten
          </button>
        ) : null}

        {vorlesenAktiv && stimme.moeglich ? (
          <Vorlesetaste
            laeuft={stimme.laeuft}
            angehalten={stimme.angehalten}
            gegenstand={schritt === 'antworten' ? 'Frage' : 'Antwort'}
            onSprich={() => {
              if (gesprochenerText !== null) {
                stimme.sprich(gesprochenerText);
              }
            }}
            onAbbrechen={stimme.abbrechen}
            onAnhalten={stimme.anhalten}
            onFortsetzen={stimme.fortsetzen}
          />
        ) : null}

        <button
          type="button"
          className="knopf knopf--merken"
          aria-pressed={sitzung.gemerkt}
          onClick={sitzung.merkenUmschalten}
        >
          <span aria-hidden="true">{sitzung.gemerkt ? '★' : '☆'}</span> Frage merken
        </button>

        <button type="button" className="knopf knopf--leise" onClick={sitzung.abbrechen}>
          Sitzung beenden
        </button>
      </div>

      {/*
        Der Meldeweg steht in allen drei Schritten: Ein verdrehter Wortlaut
        fällt vor der Antwort auf, ein falscher Lösungsschlüssel danach. Ein
        Knopf nur bei der Rückmeldung käme im ersten Fall zu spät.

        `key` auf die Frage: Ein von Hand aufgeklapptes `<details>` bekommt
        React nicht wieder zu – es vergleicht Eigenschaften mit Eigenschaften,
        nie mit dem DOM. Über die Identität der Frage entsteht beim Wechsel ein
        neues Element, und „eingeklappt bei der nächsten Frage“ ist keine
        Zusicherung, die jemand pflegen muss, sondern eine Folge des Aufbaus.

        Hier unten und nicht in der Aktionszeile: Die misst
        `e2e/blickfeld.spec.ts` nicht, die Marken liegen alle darüber. Ein
        fünfter Knopf in der Zeile stritte zudem bei jeder Breite mit „Antwort
        bestätigen“ um den Blick.
      */}
      <Fehlermeldeblock key={frage.id} frage={frage} katalog={katalogIndex.katalog.meta} />

      {kuerzelAktiv ? (
        <details className="sitzung__kuerzel">
          <summary>Tastenkürzel dieser Ansicht</summary>
          <p>
            <kbd>1</kbd> bis <kbd>8</kbd> wählen eine Antwortmöglichkeit, <kbd>Eingabe</kbd>{' '}
            bestätigt und geht weiter, <kbd>M</kbd> merkt die Frage. Abschaltbar unter
            „Einstellungen“ auf dem Startbildschirm.
          </p>
        </details>
      ) : null}

      {/* Ergebnisansage für Screenreader – von Anfang an im DOM vorhanden. */}
      <div className="nur-screenreader" role="status" aria-live="polite" aria-atomic="true">
        {sitzung.ansage}
      </div>
    </section>
  );
}

/** Ergebnisdarstellung – getrennt, damit der Fokus beim Aufbau greift. */
function SitzungsErgebnis({
  sitzung,
  profilId,
  katalogIndex,
  stimme,
}: {
  readonly sitzung: ReturnType<typeof useSitzung>;
  readonly profilId: number | null;
  /** Fuer die verwandten Fragen: Nummer und Text kommen aus dem Katalog. */
  readonly katalogIndex: KatalogIndex;
  /** Dieselbe Sprachausgabe wie die Vorlesetaste der Sitzung – nicht eine
      zweite: Zwei Instanzen brächen einander ab und zeigten widersprüchliche
      Zustände an. */
  readonly stimme?: Sprachausgabe;
}): React.JSX.Element | null {
  const { aktuelle, ergebnis, bewertung } = sitzung;
  /* Vor jeder frühen Rückgabe: React verlangt, dass Hooks bei jedem
     Durchlauf in derselben Reihenfolge aufgerufen werden. */
  const erklaerungen = useErklaerungen();

  if (aktuelle === null) {
    return null;
  }

  const erklaerung = erklaerungen.zu(aktuelle.frage.id);

  if (ergebnis !== null) {
    const richtige = richtigeLabels(aktuelle.frage);
    return (
      <Ergebnisbereich
        art={ergebnis.art}
        symbol={ERGEBNIS_SYMBOL[ergebnis.art]}
        titel={ERGEBNIS_TITEL[ergebnis.art]}
      >
        <p>{loesungssatz(richtige)}</p>
        {ergebnis.fehlend.length > 0 ? (
          <p>Nicht gewählt hatten Sie: {labelListe(ergebnis.fehlend)}.</p>
        ) : null}
        {ergebnis.zuviel.length > 0 ? (
          <p>Falsch gewählt hatten Sie: {labelListe(ergebnis.zuviel)}.</p>
        ) : null}
        {/* Bei falscher Antwort offen – dann braucht man die Begründung.
            Bei richtiger zu: Die Tafel ist 1156 Pixel hoch und drängte sonst
            „Nächste Frage“ aus dem Bild, obwohl man es schon wusste. */}
        {/* Was mit dieser Frage bisher war – die Antwort auf „Warum kommt
            die schon wieder?“. Vor der Erklärungstafel: eine Zeile, die man
            im Vorbeigehen liest, gehört über einen Block, den man aufklappt. */}
        <Fragesteckbrief frageId={aktuelle.frage.id} profilId={profilId} />

        {/* Nach dem Steckbrief, vor der Begruendung: „was war hier bisher"
            gehoert vor „was gehoert noch dazu". */}
        {erklaerung?.verwandt === undefined ? null : (
          <VerwandteFragen frageIds={erklaerung.verwandt} katalogIndex={katalogIndex} />
        )}

        {erklaerung === null ? null : (
          <Erklaerungstafel
            erklaerung={erklaerung}
            ebene={3}
            einklappbar
            {...(stimme === undefined ? {} : { stimme })}
            offen={ergebnis.art !== 'richtig'}
          />
        )}
      </Ergebnisbereich>
    );
  }

  if (bewertung !== null) {
    const art: ErgebnisArt = giltAlsRichtig(bewertung) ? 'richtig' : 'falsch';
    return (
      <Ergebnisbereich
        art={art}
        symbol={ERGEBNIS_SYMBOL[art]}
        titel={BEWERTUNG_BEZEICHNUNG[bewertung]}
      >
        <p>
          Ihre Selbstbewertung ist gespeichert. Sie steuert, wann diese Frage wieder vorgelegt wird.
        </p>
        {/* Was mit dieser Frage bisher war – die Antwort auf „Warum kommt
            die schon wieder?“. Vor der Erklärungstafel: eine Zeile, die man
            im Vorbeigehen liest, gehört über einen Block, den man aufklappt. */}
        <Fragesteckbrief frageId={aktuelle.frage.id} profilId={profilId} />

        {/* Nach dem Steckbrief, vor der Begruendung: „was war hier bisher"
            gehoert vor „was gehoert noch dazu". */}
        {erklaerung?.verwandt === undefined ? null : (
          <VerwandteFragen frageIds={erklaerung.verwandt} katalogIndex={katalogIndex} />
        )}

        {erklaerung === null ? null : (
          <Erklaerungstafel
            erklaerung={erklaerung}
            ebene={3}
            einklappbar
            {...(stimme === undefined ? {} : { stimme })}
            offen={!giltAlsRichtig(bewertung)}
          />
        )}
      </Ergebnisbereich>
    );
  }

  return null;
}
