import { useState } from 'react';

import {
  fundstelleText,
  fundstelleVorlesetext,
  GESETZ_BEZEICHNUNG,
  type Fundstelle,
} from '../../../../shared/erklaerungen';
import { auszugBilden, gesetzFinden, type Normauszug } from '../../../../shared/normtexte';
import { useNormtexte } from '../../hooks/useNormtexte';

export interface NormstelleProps {
  readonly fundstelle: Fundstelle;
}

/**
 * Eine Fundstelle – zum Aufklappen, mit dem Normtext darunter.
 *
 * ## Warum es das gibt
 *
 * Bis 0.22.0 stand unter jeder Erklärung „Im Gesetz nachlesen" und darunter
 * eine Liste von Zitaten ohne Sprungziel. Eine Software, die ausdrücklich
 * vollständig offline arbeitet, forderte damit zu etwas auf, das offline
 * gerade nicht ging: Ein Normtext lag nicht bei.
 *
 * ## Wortlaut
 *
 * Der Text ist der amtliche, unverändert übernommen (§ 5 Abs. 1 UrhG). Er
 * wird nie beschnitten: Bei Anlagen zeigt die Anzeige den getroffenen
 * Gliederungsblock – und wenn die Stelle sich nicht eindeutig auflösen lässt,
 * die ganze Anlage samt Hinweis, statt an eine womöglich falsche Stelle zu
 * springen.
 *
 * ## Warum `<details>`
 *
 * Tastatur, Bildschirmleser-Ansage und die Suche des Browsers in
 * zugeklapptem Inhalt bringt es von Haus aus mit. Der Inhalt entsteht erst
 * beim Aufklappen: Eine Auswertung führt bis zu 80 Fragen mit je mehreren
 * Fundstellen auf, und Anlage 1 des WaffG allein hat 29 000 Zeichen.
 */
export function Normstelle({ fundstelle }: NormstelleProps): React.JSX.Element {
  const { normtexte, vorhanden } = useNormtexte();
  const [offen, setzeOffen] = useState(false);

  const zitat = fundstelleText(fundstelle);
  const vorlesetext = fundstelleVorlesetext(fundstelle);

  /* Ohne mitgelieferte Normtexte bleibt es beim Zitat. Ein leerer Aufklapper
     verspräche etwas, das nicht da ist. */
  if (!vorhanden) {
    return (
      <>
        <span aria-hidden="true">{zitat}</span>
        <span className="nur-screenreader">{vorlesetext}</span>
      </>
    );
  }

  return (
    <details
      className="normstelle"
      onToggle={(ereignis) => {
        setzeOffen(ereignis.currentTarget.open);
      }}
    >
      {/*
        Der sichtbare Wortlaut steht **im** zugänglichen Namen und wird nicht
        durch die Sprechform ersetzt.

        Bis 0.24.1 war das Zitat hier `aria-hidden`, und der Name lautete
        allein „Paragraf 12 Absatz 1 Nummer 3 Buchstabe b Waffengesetz im
        Wortlaut anzeigen“. Sichtbar stand „§ 12 Abs. 1 Nr. 3 Buchst. b
        WaffG“ – kein einziger dieser Bestandteile kam im Namen vor. Wer die
        Anwendung mit der Stimme bedient und sagt, was er liest, traf das
        Bedienelement nicht (WCAG 2.5.3, Fehlerfigur F96).

        Angehängt statt ersetzt, wie in `FrageKopf`: Der sichtbare Text
        kommt zuerst, die Aussprachehilfe dahinter. Komma davor, weil bei der
        Namensberechnung der führende Leerraum eines Elements wegfällt.
      */}
      <summary className="normstelle__zitat">
        {zitat}
        <span className="nur-screenreader">, {vorlesetext}, im Wortlaut anzeigen</span>
      </summary>
      {offen ? <Normauszugsanzeige fundstelle={fundstelle} normtexte={normtexte} /> : null}
    </details>
  );
}

function Normauszugsanzeige({
  fundstelle,
  normtexte,
}: {
  readonly fundstelle: Fundstelle;
  readonly normtexte: ReturnType<typeof useNormtexte>['normtexte'];
}): React.JSX.Element {
  const auszug = auszugBilden(normtexte, fundstelle);
  const gesetz = gesetzFinden(normtexte, fundstelle.gesetz);

  return (
    <div className="normstelle__text">
      {inhalt(auszug)}
      {/* Der Stand gehört dazu: Ein Gesetzestext ohne Fassungsangabe ist eine
          Behauptung über heute, die morgen falsch sein kann. */}
      <p className="normstelle__herkunft">
        {GESETZ_BEZEICHNUNG[fundstelle.gesetz]}
        {gesetz === null ? '' : ` – ${gesetz.stand}`}. Amtlicher Wortlaut, unverändert übernommen.
      </p>
    </div>
  );
}

function inhalt(auszug: Normauszug): React.JSX.Element {
  switch (auszug.art) {
    case 'fehlt':
      return (
        <p className="normstelle__fehlt">
          Zu dieser Fundstelle liegt kein Text bei. Das Zitat oben bleibt gültig.
        </p>
      );

    case 'absatz':
      return (
        <>
          {auszug.titel.length > 0 ? <p className="normstelle__titel">{auszug.titel}</p> : null}
          <p className="normstelle__absatz">
            ({auszug.absatz}) {auszug.text}
          </p>
        </>
      );

    case 'norm':
      return (
        <>
          {auszug.titel.length > 0 ? <p className="normstelle__titel">{auszug.titel}</p> : null}
          <p className="normstelle__absatz">{auszug.text}</p>
        </>
      );

    case 'block':
      return (
        <>
          {auszug.block.pfad.length > 0 ? (
            <p className="normstelle__pfad">{auszug.block.pfad.join(' – ')}</p>
          ) : null}
          <p className="normstelle__absatz">{auszug.block.text}</p>
        </>
      );

    case 'anlage':
      return (
        <>
          <p className="normstelle__unscharf">
            {auszug.abbildung
              ? `Die angegebene Stelle „${auszug.stelle}“ ist eine Abbildung. Der amtliche ` +
                'Gesetzestext führt sie nur als Bildunterschrift, die Bilder selbst gehören ' +
                'nicht dazu und liegen dieser Anwendung nicht bei.'
              : `Die angegebene Stelle „${auszug.stelle}“ ließ sich im Text der Anlage nicht ` +
                'eindeutig auffinden. Damit nichts an der falschen Stelle steht, folgt die ' +
                'Anlage vollständig.'}
          </p>
          {/* Eingeklappt: Anlage 1 des WaffG hat 29 000 Zeichen. Wer sie
              braucht, klappt sie auf; wer die Auskunft oben gelesen hat,
              scrollt nicht daran vorbei. */}
          <details className="normstelle__ganze">
            <summary>Ganze Anlage anzeigen</summary>
            <div className="normstelle__anlage">
              {auszug.bloecke.map((block, i) => (
                <p key={`${block.marke ?? 'vorspann'}-${String(i)}`} className="normstelle__absatz">
                  {block.text}
                </p>
              ))}
            </div>
          </details>
        </>
      );
  }
}
