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

import type { OffenerLauf } from '../../../../shared/pruefung';
import { useFokusBeimAufbau } from '../../hooks/useFokusBeimAufbau';
import { wirksameZeitMinuten } from '../../pruefung/auftrag';
import { restzeitText, zeitpunktText } from '../../pruefung/zeit';
import { Hinweis } from '../lernen/Hinweis';

type Rueckfrage = 'keine' | 'fortsetzen' | 'verwerfen';

export interface UnterbrochenProps {
  readonly lauf: OffenerLauf;
  /** Setzt die Simulation fort – erst nach ausdrücklicher Bestätigung. */
  readonly onFortsetzen: () => void;
  /** Verwirft ihn im Anwendungskern. */
  readonly onVerwerfen: () => Promise<void>;
}

/** Wie viele Fragen des Bogens eine Eingabe tragen. */
function beantwortete(lauf: OffenerLauf): number {
  return lauf.bogen.filter((eintrag) => {
    const eingabe = lauf.eingaben[eintrag.frageId];
    if (eingabe === undefined) {
      return false;
    }
    return eingabe.auswahl.length > 0 || eingabe.freitext.trim().length > 0;
  }).length;
}

/**
 * Die unterbrochene Simulation.
 *
 * **Warum es diese Karte gibt.** Eine Simulation läuft bis zu zwei Stunden.
 * Wer zwischendurch das Fenster schließt oder dem Rechner der Strom ausgeht,
 * verlor bisher alles. Der Anwendungskern hält den Bogen jetzt fest – hier
 * ist der Weg zurück hinein.
 *
 * **Warum kein Klick die Uhr anwirft.** Die Karte drängt sich beim Start
 * ungefragt zwischen die täglichen Schaltflächen. Ein Fehlgriff auf
 * „Fortsetzen“ dürfte deshalb nichts kosten: Er führt auf eine Rückfrage, die
 * sagt, wie viel Zeit bleibt, und erst deren Hauptschaltfläche lässt die Uhr
 * weiterlaufen. Bis dahin ist die Karte selbst der Ruhepunkt.
 *
 * **Warum das Verwerfen ebenfalls fragt.** Es wirft bis zu zwei Stunden Arbeit
 * weg und lässt sich nicht rückgängig machen (WCAG 3.3.4). Anders als bei der
 * Abgabe ist hier das Behalten die Hauptschaltfläche: Dort hat der Prüfling
 * den Schritt selbst angestoßen, hier steht die Karte ungefragt da.
 */
export function Unterbrochen({
  lauf,
  onFortsetzen,
  onVerwerfen,
}: UnterbrochenProps): React.JSX.Element {
  const titelId = useId();
  const [rueckfrage, setzeRueckfrage] = useState<Rueckfrage>('keine');
  const [fehler, setzeFehler] = useState<string | null>(null);

  /*
    Der Weg zurück: Verschwindet eine Rückfrage, gehört der Fokus auf den
    Knopf, der sie geöffnet hat – nicht auf `<body>`. Über eine
    Rückruf-Referenz statt über eine Merkliste von Knoten: Der Knopf meldet
    sich, sobald er wieder da ist, und nimmt den Fokus im selben Zug mit.
  */
  const [fokusZiel, setzeFokusZiel] = useState<Rueckfrage>('keine');

  const knopfRef =
    (welche: Rueckfrage) =>
    (element: HTMLButtonElement | null): void => {
      if (element !== null && fokusZiel === welche) {
        element.focus();
        setzeFokusZiel('keine');
      }
    };

  const schliessen = useCallback((welche: Rueckfrage) => {
    setzeRueckfrage('keine');
    setzeFokusZiel(welche);
  }, []);

  const gesamt = lauf.bogen.length;
  const fertig = beantwortete(lauf);
  const stelle = Math.min(lauf.position + 1, gesamt);

  /* Die **wirksame** Zeit, nicht die des Profils: Der Zeitmodus schlägt beim
     Nachteilsausgleich 25 oder 50 Prozent auf, und `wirksameZeitMinuten` ist
     dieselbe Rechnung, mit der der laufende Bogen arbeitet
     (`usePruefung.ts`). Bis 0.24.1 stand hier `lauf.profil.zeitMinuten` roh –
     wer „plus 50 Prozent" gewählt hatte, bekam ein Drittel zu wenig
     angezeigt, ausgerechnet in dem Merkmal, das WCAG 2.2.1 bedient.
     `null` heißt: dieses Profil sieht keine Uhr vor. */
  const zeitMinuten = wirksameZeitMinuten(lauf.profil, lauf.auftrag);
  /* Ein abgegebener Bogen, bei dem nur noch die offenen Fragen zu bewerten
     sind: Die Uhr steht endgültig, und es geht bei keiner Frage weiter. Die
     Karte sagte bis 0.24.1 auch hier „Frage 40 von 100“ und „23 Minuten
     bleiben“ – drei Angaben, von denen nach dem Klick keine zutraf. */
  const nurNochBewerten = lauf.phase === 'nachbewertung';
  const mitUhr = !nurNochBewerten && zeitMinuten !== null && zeitMinuten > 0;
  const restMs = mitUhr ? Math.max(0, zeitMinuten * 60_000 - lauf.verbrauchtMs) : 0;

  return (
    <section className="karte abschnitt unterbrochen" aria-labelledby={titelId}>
      <h2 id={titelId}>Unterbrochene Simulation</h2>

      <dl className="unterbrochen__daten">
        <div>
          <dt>Profil</dt>
          <dd>{lauf.profil.name}</dd>
        </div>
        <div>
          <dt>Stand</dt>
          <dd>
            {nurNochBewerten
              ? `Abgegeben, ${String(fertig)} von ${String(gesamt)} beantwortet – die offenen Fragen sind noch zu bewerten`
              : `Frage ${String(stelle)} von ${String(gesamt)}, ${String(fertig)} beantwortet`}
          </dd>
        </div>
        <div>
          <dt>Verbleibende Zeit</dt>
          <dd>
            {nurNochBewerten
              ? 'Die Zeit ist abgeschlossen'
              : mitUhr
                ? restzeitText(restMs)
                : 'Ohne Zeitbegrenzung'}
          </dd>
        </div>
        <div>
          <dt>Unterbrochen</dt>
          <dd>{zeitpunktText(lauf.gesichertAm)}</dd>
        </div>
      </dl>

      {mitUhr ? (
        <p className="unterbrochen__uhr">
          Die Uhr stand still, während das Programm zu war. Sie läuft erst weiter, wenn Sie die
          Simulation fortsetzen.
        </p>
      ) : null}

      {rueckfrage === 'fortsetzen' ? (
        <Rueckfragebereich
          titel={nurNochBewerten ? 'Bewertung jetzt abschließen?' : 'Simulation jetzt fortsetzen?'}
          text={
            nurNochBewerten
              ? 'Der Bogen ist abgegeben und die Zeit abgeschlossen. Es bleibt, Ihre eigenen Antworten auf die offenen Fragen zu bewerten; danach kommt die Auswertung.'
              : mitUhr
                ? `Sie machen bei Frage ${String(stelle)} von ${String(gesamt)} weiter. Ab dem Klick läuft die Uhr: ${restzeitText(restMs)} bleiben.`
                : `Sie machen bei Frage ${String(stelle)} von ${String(gesamt)} weiter. Diese Simulation hat keine Zeitbegrenzung.`
          }
          hauptText={nurNochBewerten ? 'Jetzt bewerten' : 'Jetzt fortsetzen'}
          hauptArt="haupt"
          nebenText="Noch nicht"
          onHaupt={onFortsetzen}
          onNeben={() => {
            schliessen('fortsetzen');
          }}
        />
      ) : null}

      {rueckfrage === 'verwerfen' ? (
        <Rueckfragebereich
          titel="Unterbrochene Simulation verwerfen?"
          text={`Damit sind ${String(fertig)} beantwortete Fragen dieser Simulation weg, begonnen am ${zeitpunktText(lauf.begonnenAm)}. Das lässt sich nicht rückgängig machen; in Ihrem Verlauf erscheint sie dann nicht.`}
          hauptText="Nein, Simulation behalten"
          hauptArt="haupt"
          nebenText="Ja, Simulation verwerfen"
          nebenArt="warnung"
          onHaupt={() => {
            schliessen('verwerfen');
          }}
          onNeben={() => {
            void onVerwerfen().catch((grund: unknown) => {
              setzeFehler(
                grund instanceof Error
                  ? `Die Simulation konnte nicht verworfen werden. (${grund.message})`
                  : 'Die Simulation konnte nicht verworfen werden.',
              );
              schliessen('verwerfen');
            });
          }}
        />
      ) : null}

      {rueckfrage === 'keine' ? (
        <div className="unterbrochen__aktionen">
          <button
            type="button"
            className="knopf knopf--haupt"
            ref={knopfRef('fortsetzen')}
            onClick={() => {
              setzeFehler(null);
              setzeRueckfrage('fortsetzen');
            }}
          >
            {nurNochBewerten ? 'Bewertung abschließen' : 'Simulation fortsetzen'}
          </button>
          <button
            type="button"
            className="knopf"
            ref={knopfRef('verwerfen')}
            onClick={() => {
              setzeFehler(null);
              setzeRueckfrage('verwerfen');
            }}
          >
            Simulation verwerfen
          </button>
        </div>
      ) : null}

      {fehler === null ? null : (
        <Hinweis art="fehler" alsMeldung>
          {fehler}
        </Hinweis>
      )}
    </section>
  );
}

/** Rückfrage im Textfluss – dasselbe Muster wie „Neu anfangen“. */
function Rueckfragebereich({
  titel,
  text,
  hauptText,
  hauptArt,
  nebenText,
  nebenArt,
  onHaupt,
  onNeben,
}: {
  readonly titel: string;
  readonly text: string;
  readonly hauptText: string;
  readonly hauptArt: 'haupt';
  readonly nebenText: string;
  readonly nebenArt?: 'warnung';
  readonly onHaupt: () => void;
  readonly onNeben: () => void;
}): React.JSX.Element {
  const bereichRef = useFokusBeimAufbau<HTMLDivElement>();
  const titelId = useId();

  return (
    <div
      className="unterbrochen__rueckfrage"
      ref={bereichRef}
      tabIndex={-1}
      role="group"
      aria-labelledby={titelId}
      aria-describedby={`${titelId}-text`}
    >
      <h3 className="unterbrochen__rueckfrage-titel" id={titelId}>
        {titel}
      </h3>
      <p id={`${titelId}-text`}>{text}</p>

      <div className="unterbrochen__rueckfrage-aktionen">
        <button type="button" className={`knopf knopf--${hauptArt}`} onClick={onHaupt}>
          {hauptText}
        </button>
        <button
          type="button"
          className={nebenArt === undefined ? 'knopf' : `knopf knopf--${nebenArt}`}
          onClick={onNeben}
        >
          {nebenText}
        </button>
      </div>
    </div>
  );
}
