/**
 * Fragen über ihre Nummer nachschlagen.
 *
 * ## Warum das ein eigenes Modul ist
 *
 * Weil es eine eigene Fehlerquelle ist. Der Katalog führt **zwei**
 * Nummernformate nebeneinander, und beide haben ihre Tücken:
 *
 * * Kapitel I nummeriert abschnittsweise: `1.01` bis `2.150`, als Kennung
 *   `I.1-01` bis `I.2-150`.
 * * Kapitel II, III und IV zählen jeweils bei `01` neu, als Kennung `II-01`,
 *   `III-01`, `IV-01`.
 *
 * Daraus folgen zwei Dinge, die man leicht falsch macht:
 *
 * **Führende Nullen.** Wer `2.5` tippt, meint Frage `2.05`. Eine
 * Präfixsuche lieferte ihm still die Fragen `2.50` bis `2.59` – also das
 * Falsche statt nichts. Deshalb werden beide Seiten gleich normalisiert:
 * führende Nullen der Laufnummer fallen weg, hier wie dort.
 *
 * **Mehrdeutigkeit.** Von 437 verschiedenen Nummern sind **89 mehrdeutig** –
 * eine bloße `45` gibt es in Kapitel II, III und IV. Die Anwendung wählt
 * nicht heimlich eine aus, sondern zeigt alle drei nebeneinander, jede mit
 * ihrer Kapitelzeile.
 *
 * ## Ausdrücklich keine Teilzeichenkettensuche
 *
 * Die Nummern der Kapitel II bis IV sind zweistellig aufgefüllt. Eine
 * Teilzeichenkettensuche nach `05` höbe sechs Fragen über jeden Texttreffer.
 * Ein Nummerntreffer entsteht nur bei Gleichheit nach Normalisierung.
 */

import type { Katalog } from './katalog';

/** Höflichkeitsfloskeln, die vor einer Nummer stehen können. */
const VORSPANN = /^(frage|nr\.?|nummer)\s*/u;

/** `2.5`, `2,05`, `2.150` – die Zählweise des Kapitels I. */
const MIT_ABSCHNITT = /^([1-9])[.,]0*(\d{1,3})$/u;

/** `45`, `05`, `5` – die Zählweise der Kapitel II bis IV. */
const BLOSSE_NUMMER = /^0*(\d{1,3})$/u;

/** `I.2-150`, `II-45`, `ii 45` – die vollständige Kennung. */
const KENNUNG = /^(i[.,]([1-5])|ii|iii|iv)[-– ]0*(\d{1,3})$/u;

/**
 * Bringt eine Eingabe auf einen Nachschlageschlüssel.
 *
 * Liefert `null`, wenn die Eingabe nicht wie eine Nummer aussieht – dann
 * bleibt es bei der Textsuche.
 */
export function nummerSchluessel(roh: string): string | null {
  const t = roh.trim().toLowerCase().replace(/\s+/gu, ' ').replace(VORSPANN, '').trim();

  const kennung = KENNUNG.exec(t);
  if (kennung !== null) {
    const kapitel = kennung[2] === undefined ? (kennung[1] ?? '') : `i.${kennung[2]}`;
    return `kennung:${kapitel}-${kennung[3] ?? ''}`;
  }

  const mitAbschnitt = MIT_ABSCHNITT.exec(t);
  if (mitAbschnitt !== null) {
    return `nummer:${mitAbschnitt[1] ?? ''}.${mitAbschnitt[2] ?? ''}`;
  }

  const bloss = BLOSSE_NUMMER.exec(t);
  if (bloss !== null) {
    return `nummer:${bloss[1] ?? ''}`;
  }

  return null;
}

/** Der Schlüssel, unter dem eine Frage selbst zu finden ist. */
function schluesselDerFrage(kennung: string, nummer: string): readonly string[] {
  const aus: string[] = [];

  // Kennung: „I.2-150“ → „kennung:i.2-150“, „II-45“ → „kennung:ii-45“.
  const teile = /^(i\.[1-5]|ii|iii|iv)-0*(\d{1,3})$/u.exec(kennung.toLowerCase());
  if (teile !== null) {
    aus.push(`kennung:${teile[1] ?? ''}-${teile[2] ?? ''}`);
  }

  // Amtliche Nummer: „1.01“ → „nummer:1.1“, „45“ → „nummer:45“.
  const mitAbschnitt = MIT_ABSCHNITT.exec(nummer);
  if (mitAbschnitt !== null) {
    aus.push(`nummer:${mitAbschnitt[1] ?? ''}.${mitAbschnitt[2] ?? ''}`);
  } else {
    const bloss = BLOSSE_NUMMER.exec(nummer);
    if (bloss !== null) {
      aus.push(`nummer:${bloss[1] ?? ''}`);
    }
  }

  return aus;
}

export interface Nummernindex {
  readonly nach: ReadonlyMap<string, readonly string[]>;
}

export function nummernindexBauen(katalog: Katalog): Nummernindex {
  const nach = new Map<string, string[]>();
  for (const frage of katalog.fragen) {
    for (const schluessel of schluesselDerFrage(frage.id, frage.amtliche_nummer)) {
      const liste = nach.get(schluessel) ?? [];
      liste.push(frage.id);
      nach.set(schluessel, liste);
    }
  }
  return { nach };
}

/**
 * Die Fragen zu einer Nummerneingabe – in Katalogreihenfolge.
 *
 * Leere Liste heißt: Die Eingabe sah nicht wie eine Nummer aus oder es gibt
 * die Nummer nicht. Beides ist kein Fehler; die Textsuche läuft ohnehin
 * darunter weiter.
 */
export function nummernTreffer(index: Nummernindex, eingabe: string): readonly string[] {
  const schluessel = nummerSchluessel(eingabe);
  if (schluessel === null) {
    return [];
  }
  return index.nach.get(schluessel) ?? [];
}
