import { useMemo } from 'react';

import type { Rangklasse } from '../../../../shared/fragensuche';
import { spannenFinden } from '../../../../shared/hervorhebung';
import type { Frage } from '../../../../shared/katalog';
import { RichTextAnzeige } from '../lernen/RichTextAnzeige';

export interface TrefferkarteProps {
  readonly frage: Frage;
  readonly kapitelTitel: string;
  readonly abschnittTitel: string | null;
  /** `null` beim Stöbern: Dann gibt es keine Fundstelle zu benennen. */
  readonly klasse: Rangklasse | 'nummer' | null;
  /** Labels der Antwortmöglichkeiten mit Fundstelle. */
  readonly optionenMitTreffer: readonly string[];
  /** Steht mindestens ein Suchwort auch im sichtbaren Fragetext? */
  readonly auchImFragetext: boolean;
  /** Die gefalteten Suchwörter – Grundlage der Hervorhebung. */
  readonly woerter: readonly string[];
  /** Setzt den Fokus hierher, wenn nachgeladen wurde. */
  readonly titelRef?: React.RefObject<HTMLHeadingElement | null> | undefined;
  readonly onUeben: () => void;
}

/**
 * Sagt im Klartext, wo der Treffer sitzt.
 *
 * Die Rangfolge steht damit nicht nur in der Reihenfolge, sondern an jedem
 * einzelnen Treffer – lesbar und hörbar. Das ist der Ersatz für einen
 * Punktwert wie bm25: Wer die Liste hört, kann eine Sortierung nicht
 * überblicken, aber er kann einen Satz verstehen.
 */
function fundstellenzeile(
  klasse: Rangklasse | 'nummer',
  optionen: readonly string[],
  auchImFragetext: boolean,
): string {
  switch (klasse) {
    case 'nummer':
      return 'Über die Fragennummer gefunden.';
    case 'frage-anfang':
      return 'Treffer im Fragetext.';
    case 'frage-innen':
      return 'Treffer im Fragetext, im Wortinneren.';
    case 'antwort':
      if (optionen.length === 0) {
        return 'Treffer in einer Antwortmöglichkeit.';
      }
      if (optionen.length === 1) {
        return `Treffer in Antwortmöglichkeit ${optionen[0] ?? ''}.`;
      }
      return `Treffer in den Antwortmöglichkeiten ${optionen.slice(0, -1).join(', ')} und ${
        optionen[optionen.length - 1] ?? ''
      }.`;
    case 'muster':
      /*
        Die Unterscheidung ist keine Feinheit, sondern eine Berichtigung: Bei
        einer mehrteiligen Anfrage kann ein Wort sichtbar im Fragetext stehen
        und markiert sein, während nur das andere in der Musterantwort liegt.
        „Treffer NUR in der Musterantwort“ widerspräche dann der Marke, die
        der Nutzer vor sich sieht – und die Zeile ist gerade der Ersatz für
        das, was er nicht sehen kann.
      */
      return auchImFragetext
        ? 'Ein Teil der Suchwörter steht nur in der Musterantwort – sie wird hier nicht gezeigt.'
        : 'Treffer nur in der Musterantwort – sie wird hier nicht gezeigt.';
  }
}

/**
 * Eine Frage in der Trefferliste.
 *
 * ## Was hier bewusst NICHT steht
 *
 * **Die Musterantwort.** Bei den 103 offenen Fragen ist sie die Lösung. Sie
 * wird durchsucht, damit die Suche vollständig ist, aber nie gezeigt – auch
 * nicht hinter einem Aufklapper.
 *
 * **Welche Antwort richtig ist.** Die Antwortmöglichkeiten lassen sich
 * aufklappen, weil ohne sie oft nicht erkennbar ist, worum die Frage geht.
 * Das Feld `korrekt` wird dabei nirgends gelesen; ein Test prüft, dass es im
 * Baum nicht auftaucht.
 *
 * ## Zur Hervorhebung
 *
 * `<mark className="kernelement">` ist in dieser Anwendung bereits vergeben –
 * `Musterantwort.tsx` benutzt es. Zwei Marken mit zwei Bedeutungen und
 * praktisch einer Darstellung wären ein Fehler: Ein Bildschirmleser meldet
 * für beide nur „hervorgehoben“. Weil die Musterantwort hier ohnehin nicht
 * erscheint, ist `<mark className="fundstelle">` die einzige Marke dieser
 * Ansicht und trägt genau eine Bedeutung. Die amtlichen Auszeichnungen des
 * Wortlauts bleiben `<strong>`.
 */
export function Trefferkarte({
  frage,
  kapitelTitel,
  abschnittTitel,
  klasse,
  optionenMitTreffer,
  auchImFragetext,
  woerter,
  titelRef,
  onUeben,
}: TrefferkarteProps): React.JSX.Element {
  const frageSpannen = useMemo(
    () => spannenFinden(frage.frage.text, woerter),
    [frage.frage.text, woerter],
  );

  const optionen = frage.optionen ?? [];
  const einordnung =
    abschnittTitel === null
      ? `Kapitel ${frage.kapitel} – ${kapitelTitel}`
      : `${frage.abschnitt ?? ''} – ${abschnittTitel}`;

  return (
    <li className="treffer">
      <p className="treffer__einordnung">
        Frage {frage.amtliche_nummer} · {einordnung}
      </p>

      {/* tabIndex={-1}: Nach „Weitere anzeigen“ wandert der Fokus hierher –
          die neuen Karten stehen im Baum vor dem Knopf und würden beim
          Weitertabben sonst vollständig übersprungen. */}
      <h2 className="treffer__frage" ref={titelRef} tabIndex={-1}>
        <RichTextAnzeige text={frage.frage} art="hervorhebung" fundstellen={frageSpannen} />
      </h2>

      {klasse === null ? null : (
        <p className="treffer__fundstelle">
          {fundstellenzeile(klasse, optionenMitTreffer, auchImFragetext)}
        </p>
      )}

      {optionen.length === 0 ? null : (
        <details className="treffer__optionen">
          {/* Ohne Überschrift im summary: Zugeklappte <details> zählen in
              `ueberschriften.spec.ts` mit, eine Überschrift hier bräche die
              Hierarchie der Ansicht. */}
          <summary>Antwortmöglichkeiten anzeigen ({optionen.length})</summary>
          <ol className="treffer__optionenliste">
            {optionen.map((option) => (
              <li key={option.label}>
                <span className="treffer__label">{option.label})</span>{' '}
                {option.inhalt.text.trim().length === 0 ? (
                  <em>Diese Antwort besteht aus einem Bild.</em>
                ) : (
                  <RichTextAnzeige
                    text={option.inhalt}
                    art="hervorhebung"
                    fundstellen={spannenFinden(option.inhalt.text, woerter)}
                  />
                )}
              </li>
            ))}
          </ol>
        </details>
      )}

      <div className="treffer__aktionen">
        {/* Voller Name im Knopftext: „Üben“ neben einer Überschrift wäre für
            eine Bedienelementliste nichtssagend (WCAG 2.4.6). */}
        <button type="button" className="knopf" onClick={onUeben}>
          Frage {frage.amtliche_nummer} üben
        </button>
      </div>
    </li>
  );
}
