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

import { KONTAKT } from '../../../../shared/kontakt';
import {
  meldetextBauen,
  type MeldeFrage,
  type MeldeKatalog,
  type MeldeProgramm,
} from '../../../../shared/meldetext';
import { bridge } from '../../bridge';
import { programmangabenHolen } from '../../lernen/programmangaben';

export interface FehlermeldeblockProps {
  readonly frage: MeldeFrage;
  readonly katalog: MeldeKatalog;
}

/**
 * „Fehler zu dieser Frage melden“ – der kurze Weg aus der Sitzung heraus.
 *
 * ## Warum der Text sichtbar ist, bevor er kopiert wird
 *
 * Er verlässt später das Gerät. Wer ihn weitergibt, muss vorher lesen können,
 * was drinsteht – das ist keine Höflichkeit, sondern die einzige Art, eine
 * Zusage wie „nichts über Sie“ überprüfbar zu machen. Deshalb steht der Text
 * im Feld und der Knopf daneben, nicht umgekehrt.
 *
 * Aus demselben Grund wird genau die Zeichenkette kopiert, die im Feld steht:
 * Sie wird einmal gebaut und dann sowohl angezeigt als auch übergeben. „Was
 * du gesehen hast, ist was du kopiert hast“ gilt hier per Konstruktion und
 * nicht per Absicht.
 *
 * ## Warum die Zwischenablage über den Anwendungskern läuft
 *
 * Weil der Renderer sie nicht bekommt. Nachgemessen im gebauten Fenster:
 * `isSecureContext` ist `true`, `navigator.clipboard.writeText` existiert –
 * und der Aufruf endet mit `NotAllowedError: Write permission denied`, weil
 * `sicherheit.ts` mit `setPermissionCheckHandler(() => false)` sämtliche
 * Berechtigungen ablehnt. Den Wächter dafür zu öffnen gäbe die Zwischenablage
 * jedem Renderer-Code frei; ein Kanal mit fester Nutzlast ist der kleinere
 * Eingriff.
 *
 * ## Warum die Beschriftung „Fehler zu dieser Frage melden“ lautet
 *
 * „Fehler melden“ allein steht in der Rückmeldung direkt neben dem Wort
 * „Falsch“ und läse sich dort als *meinen* Fehler vermerken. Der Zusatz
 * beseitigt die Verwechslung für alle – ein nur für Bildschirmleser
 * sichtbarer Zusatz hülfe gerade denen nicht, die sie machen.
 */
export function Fehlermeldeblock({ frage, katalog }: FehlermeldeblockProps): React.JSX.Element {
  const feldId = useId();
  const [ansage, setzeAnsage] = useState('');
  const [programm, setzeProgramm] = useState<MeldeProgramm | null>(null);

  useEffect(() => {
    let abgebrochen = false;
    void programmangabenHolen().then((angaben) => {
      if (!abgebrochen) {
        setzeProgramm(angaben);
      }
    });
    return () => {
      abgebrochen = true;
    };
  }, []);

  const text = programm === null ? null : meldetextBauen(frage, katalog, programm);
  const kopieren = bridge()?.zwischenablageSchreiben;

  return (
    <details className="meldung">
      <summary className="meldung__titel">Fehler zu dieser Frage melden</summary>

      <p className="meldung__hinweis">
        Stimmt an dieser Frage, ihrer Lösung oder ihrer Erklärung etwas nicht? Der folgende Text
        nennt alles, was zur Bearbeitung nötig ist. Schreiben Sie darunter, was Ihnen aufgefallen
        ist, und schicken Sie ihn an <strong>{KONTAKT.epost}</strong> – Sie bekommen eine Antwort{' '}
        {KONTAKT.frist}.
      </p>

      <label className="meldung__beschriftung" htmlFor={feldId}>
        Meldetext
      </label>
      {/*
        Schreibgeschützt, aber nicht gesperrt: `readOnly` nimmt den Fokus
        nicht und lässt Markieren und Strg+C zu. `disabled` täte beides nicht –
        und wäre damit ausgerechnet der Weg, der ohne Zwischenablage übrig
        bleibt.

        Der fertige Text erscheint erst, wenn er vollständig ist: Ein Text, der
        sich unter der Hand noch ändert, widerspräche der Zusage, dass kopiert
        wird, was dasteht.
      */}
      <textarea
        className="meldung__feld"
        id={feldId}
        readOnly
        rows={9}
        value={text ?? 'Der Meldetext wird zusammengestellt …'}
        spellCheck={false}
      />

      <div className="meldung__aktionen">
        {/*
          Ohne Kanal kein Knopf – nicht ein gesperrter. Gesperrte
          Bedienelemente nehmen keinen Fokus, ihre Erklärung würde nie
          vorgelesen. Der Text steht ohnehin da und lässt sich mit Strg+C
          nehmen; das sagt der Satz daneben.
        */}
        {text === null ? null : kopieren === undefined ? (
          <p className="meldung__ersatz">
            Das Kopieren über die Schaltfläche steht hier nicht zur Verfügung. Markieren Sie den
            Text im Feld und kopieren Sie ihn mit <kbd>Strg</kbd> + <kbd>C</kbd>.
          </p>
        ) : (
          <button
            type="button"
            className="knopf"
            onClick={() => {
              /* Vor jedem Versuch leeren: Bliebe die alte Meldung stehen,
                 meldete ein Bildschirmleser beim zweiten Fehlschlag den
                 Erfolg von vorhin. */
              setzeAnsage('');
              void kopieren(text)
                .then((erfolg) => {
                  setzeAnsage(
                    erfolg
                      ? 'Der Meldetext liegt in der Zwischenablage.'
                      : 'Der Meldetext konnte nicht kopiert werden. Markieren Sie ihn im Feld und kopieren Sie ihn mit Strg und C.',
                  );
                })
                .catch(() => {
                  setzeAnsage(
                    'Der Meldetext konnte nicht kopiert werden. Markieren Sie ihn im Feld und kopieren Sie ihn mit Strg und C.',
                  );
                });
            }}
          >
            Text kopieren
          </button>
        )}

        {/* Eine Region für beide Ausgänge, damit nie eine alte Erfolgsmeldung
            neben einem neuen Fehlschlag stehen bleibt. */}
        <p className="meldung__ansage" role="status">
          {ansage}
        </p>
      </div>
    </details>
  );
}
