/**
 * Datentypen des Lernstands.
 *
 * Der Lernstand liegt ausschließlich lokal in einer SQLite-Datei je Profil.
 * Es gibt kein Konto, keine Cloud und keine Telemetrie.
 */

import type { Reifestufe } from './reife';

/**
 * Selbst- bzw. Systembewertung einer Antwort.
 *
 * Die vier Stufen entsprechen den Bewertungen des FSRS-Verfahrens, das später
 * die Wiedervorlage plant. Bei Multiple Choice werden sie automatisch
 * vergeben, bei offenen Fragen wählt der Lernende selbst.
 */
export type Bewertung = 'nochmal' | 'schwer' | 'gut' | 'leicht';

export const BEWERTUNGEN: readonly Bewertung[] = ['nochmal', 'schwer', 'gut', 'leicht'];

export const BEWERTUNG_BEZEICHNUNG: Readonly<Record<Bewertung, string>> = Object.freeze({
  nochmal: 'Nicht gewusst',
  schwer: 'Mit Mühe gewusst',
  gut: 'Gewusst',
  leicht: 'Sicher gewusst',
});

/**
 * Welche Bewertung als gewusst zählt.
 *
 * „Nicht gewusst“ ist der einzige Fehlschlag – „mit Mühe gewusst“ ist eine
 * erfolgreiche, wenn auch mühsame Erinnerung (so rechnet auch FSRS).
 *
 * **Steht seit 0.22.0 hier und nicht mehr nur im Renderer**: Der
 * Anwendungskern braucht dieselbe Grenze für den Reife-Beleg, seit sich eine
 * richtige Auswahlantwort als geraten eingestehen lässt. Zwei Fassungen
 * derselben Regel liefen auseinander, und eine davon wäre dann die falsche.
 */
export function giltAlsRichtig(bewertung: Bewertung): boolean {
  return bewertung !== 'nochmal';
}

/** Eine beantwortete Frage, wie sie protokolliert wird. */
export interface Antwortprotokoll {
  readonly frageId: string;
  /** Bei Multiple Choice die gewählten Labels, sonst leer. */
  readonly auswahl: readonly string[];
  /** Bei offenen Fragen der eingegebene Text (kann leer bleiben). */
  readonly freitext?: string;
  readonly richtig: boolean;
  readonly bewertung: Bewertung;
  /** Bearbeitungsdauer in Millisekunden. */
  readonly dauerMs: number;
}

/** Lernstand einer einzelnen Frage. */
export interface FrageStand {
  readonly frageId: string;
  readonly versuche: number;
  readonly richtige: number;
  /** Zeitpunkt der letzten Antwort als ISO-Zeichenkette. */
  readonly zuletztBeantwortet: string | null;
  /** Fällig ab diesem Zeitpunkt; `null`, solange nie beantwortet. */
  readonly faelligAb: string | null;
  readonly gemerkt: boolean;
  /** Zuletzt vergebene Bewertung. */
  readonly letzteBewertung: Bewertung | null;
}

/** Zusammenfassung für einen Kapitel- oder Abschnittsbereich. */
export interface BereichStatistik {
  /** Kapitel- oder Abschnitts-ID, z. B. „I.2“. */
  readonly id: string;
  readonly titel: string;
  readonly fragenGesamt: number;
  readonly beantwortet: number;
  /**
   * Fragen, deren Abruf belegt ist und noch frisch – siehe `shared/reife.ts`.
   * Eine Untergrenze, keine Prognose.
   */
  readonly belegt: number;
  /** Reifegrad, 0 bis 1. `belegt` ist dieser Wert auf ganze Fragen gerundet. */
  readonly reifegrad: number;
  readonly stufe: Reifestufe;
}

/** Gesamtüberblick für den Startbildschirm. */
export interface Lernuebersicht {
  readonly fragenGesamt: number;
  readonly beantwortet: number;
  /** Siehe {@link BereichStatistik.belegt}. */
  readonly belegt: number;
  readonly reifegrad: number;
  /** Gesamtstufe, gedeckelt durch einen zurückliegenden K.-o.-Bereich. */
  readonly stufe: Reifestufe;
  /**
   * Bereiche, die das Gesamturteil deckeln – heute nur Notwehr und Notstand.
   * Leer, wenn keiner zurückliegt. Die Oberfläche nennt sie beim Namen,
   * statt nur eine Stufe tiefer zu zeigen.
   */
  readonly deckelnd: readonly string[];
  readonly faellig: number;
  readonly gemerkt: number;
  /**
   * Offene Fragen im Lernumfang – die auszuformulierenden.
   *
   * Zählt wie {@link Lernuebersicht.fragenGesamt} nur, was das Zielprofil
   * einschließt: Ohne Kapitel IV sind es 75 statt 104. Deshalb steht die
   * Zahl hier und wird nicht in der Oberfläche aus dem Katalog gerechnet –
   * dort wäre die Kapitelabwahl ein zweites Mal nachzubilden.
   */
  readonly offen: number;
  /**
   * Fragen, die zuletzt falsch beantwortet wurden.
   *
   * Dieselbe Menge, die der Einstieg „Nur Fehler“ vorlegt und die das
   * Fehlerprotokoll druckt – gebildet aus derselben Regel, damit alle drei
   * dasselbe sagen. Zählt wie {@link Lernuebersicht.fragenGesamt} nur, was
   * das Zielprofil einschließt.
   */
  readonly fehler: number;
  readonly heuteRichtig: number;
  readonly heuteFalsch: number;
  /**
   * Fragen des Lernumfangs, die heute bearbeitet wurden.
   *
   * Eine Bestandszahl aus `frage_stand`, kein Protokoll: Sie zählt
   * **verschiedene Fragen**, nicht Zeilen. Eine mit „Nicht gewusst“ bewertete
   * Frage ist sofort wieder fällig und käme sonst zweimal vor.
   */
  readonly heuteBearbeitet: number;
  /**
   * Volle Kalendertage seit der letzten Antwort; `null`, solange nie
   * beantwortet.
   *
   * Positiv für Vergangenes – anders als `tageBisTermin` im Lernplan, das
   * vorwärts rechnet. Wer nach zwei Wochen zurückkommt, sieht einen
   * gefallenen Reifegrad und ein gewachsenes Pensum; diese Zahl ist die
   * Tatsache dazu.
   */
  readonly tageSeitLetzterAntwort: number | null;
  /**
   * Wie oft Wiederholungen nach mindestens einem Tag Abstand wirklich saßen.
   *
   * **Wozu.** Der Lernplan steuert auf eine Zielquote (0,90 bis 0,97), und die
   * Reife-Ampel zeigt modellierte Abrufwahrscheinlichkeiten. Nirgends stand
   * bis 0.22.0, wie oft der Lernende fällige Wiederholungen **tatsächlich**
   * trifft. Diese Zahl schließt die Lücke zwischen der Behauptung des Modells
   * und dem Befund am Menschen — im Geist des Projekts: Messung statt
   * Behauptung.
   *
   * Eine **gemessene Vergangenheitszahl, keine Vorhersage**: Die abgelehnte
   * Bestehenswahrscheinlichkeit bleibt außen vor. Gezählt werden Antworten,
   * deren Vorgänger zur selben Frage mindestens einen Tag zurücklag —
   * dieselbe Abstandsregel, die die Belegrechnung benutzt.
   *
   * `null`, solange zu wenige solcher Wiederholungen vorliegen: Eine Quote
   * aus drei Antworten wäre eine Zahl ohne Aussage.
   */
  readonly behaltensquote?: Behaltensquote | null;
  readonly bereiche: readonly BereichStatistik[];
}

/** Die gemessene Trefferquote bei Wiederholungen mit Abstand. */
export interface Behaltensquote {
  /** Wiederholungen mit mindestens einem Tag Abstand. */
  readonly gesamt: number;
  /** Davon richtig beantwortet. */
  readonly richtig: number;
}

/** Filter für die Zusammenstellung einer Lernsitzung. */
export interface SitzungsFilter {
  /** Nur Fragen dieser Kapitel; leer bedeutet alle. */
  readonly kapitel?: readonly string[];
  /** Nur Fragen dieser Abschnitte; leer bedeutet alle. */
  readonly abschnitte?: readonly string[];
  /** Nur gemerkte Fragen. */
  readonly nurGemerkte?: boolean;
  /** Nur Fragen, die zuletzt falsch beantwortet wurden. */
  readonly nurFehler?: boolean;
  /**
   * Nur hartnäckige Fragen – solche, die wiederholt danebengingen.
   *
   * **Warum das neben {@link SitzungsFilter.nurFehler} steht und nicht an
   * seiner Stelle.** „Nur Fehler“ fragt die **letzte** Antwort: Wer eine
   * Frage gestern zufällig richtig hatte, sieht sie dort nicht mehr – und
   * das ist richtig so, das gedruckte Fehlerprotokoll sagt es ausdrücklich
   * zu („Sobald Sie eine davon wieder richtig beantworten, verschwindet sie
   * aus dieser Liste“). Dieser Filter fragt die **Historie**: Eine Frage, die
   * über Wochen viermal durchfiel und einmal saß, ist nicht gekonnt.
   *
   * Die Schwelle steht in `shared/hartnaeckig.ts`. Rein deskriptiv – gezählte
   * Fehlschläge aus dem Protokoll, keine erfundene Kennzahl.
   */
  readonly nurHartnaeckige?: boolean;
  /** Nur noch nie beantwortete Fragen. */
  readonly nurNeue?: boolean;
  /**
   * Nur offene Fragen – solche, die auszuformulieren sind.
   *
   * Der amtliche Katalog enthält davon 104 von 575, sehr ungleich verteilt:
   * Kapitel I 61, II 13, III 1, IV 29. Wer Kapitel IV abgewählt hat, behält
   * 75. Sie sind der Teil der Prüfung, den ein Mensch bewertet, und der
   * einzige, den man nicht durch Ankreuzen erraten kann.
   *
   * Anders als die drei übrigen Filter fragt dieser nicht den Lernstand,
   * sondern den Katalog: Der Fragetyp steht in `Frage.typ`, nicht in der
   * Datenbank.
   */
  readonly nurOffene?: boolean;
  /** Höchstzahl der Fragen in der Sitzung. */
  readonly anzahl?: number;
  /** Reihenfolge mischen (Vorgabe) oder Katalogreihenfolge beibehalten. */
  readonly mischen?: boolean;
  /**
   * Antwortmöglichkeiten innerhalb der Frage mischen. Vorgabe ist `false`.
   *
   * Vollständig getrennt von {@link SitzungsFilter.mischen}, weil beides
   * Unterschiedliches leistet: Die Fragenreihenfolge ist eine Frage der
   * Abwechslung und folgenlos. Die Optionsreihenfolge kostet den Gleichlauf
   * mit dem amtlichen Katalog – 83 % der Auswahlfragen erscheinen dann
   * anders als dort – und nimmt jedem den Halt, der sich die Antworten über
   * ihre Stelle merkt; bei einer Gedächtnis- oder Konzentrationsbeeinträchtigung
   * ein üblicher Weg. Ein Lernvorteil, der das aufwöge, ist nicht belegt.
   *
   * Fehlt der Wert, wird **nicht** gemischt. Früher galt hier
   * {@link SitzungsFilter.mischen} – diese Kopplung mischte die Antworten
   * still mit, sobald ein Aufrufer nur die Fragen mischen wollte.
   */
  readonly optionenMischen?: boolean;
}

/** Ein Lernprofil. Mehrere Profile teilen sich ein Gerät. */
export interface Profil {
  readonly id: number;
  readonly name: string;
  /** Prüfungstermin als ISO-Datum; steuert später den Lernplan. */
  readonly pruefungstermin: string | null;
  /**
   * Kapitel, die dieses Profil dauerhaft nicht lernt – Kennungen wie „IV“.
   *
   * Nicht jede Prüfungsstelle prüft Kapitel IV („Not- und
   * Seenotsignalmittel“). Wer es nie braucht, schleppte sonst 89 der 575
   * Fragen durch jede Zahl: Fortschritt, Tagespensum, Prognose,
   * Prüfungsreife. Die Abwahl je Simulationslauf gibt es davon getrennt und
   * wirkt nur auf den gezogenen Bogen.
   *
   * Eine **Liste**, kein Wahrheitswert: Heute ist nur Kapitel IV abwählbar,
   * aber ein `boolean` müsste beim nächsten Kapitel wieder migriert werden.
   *
   * Ausgeblendet, nicht gelöscht: Was in Kapitel IV bereits gelernt wurde,
   * bleibt im Lernstand stehen und kehrt bei Wiederwahl vollständig zurück.
   */
  readonly kapitelAusschluss: readonly string[];
  readonly erstelltAm: string;
}

/**
 * Die Antwortoptionen einer Frage in Anzeigereihenfolge – im Regelfall die
 * des amtlichen Katalogs, gemischt nur auf ausdrücklichen Wunsch. Die
 * Zuordnung bleibt in jedem Fall über die Labels erhalten: Der Buchstabe
 * gehört zum Inhalt, nicht zur Stelle.
 */
export interface SitzungsFrage {
  readonly frageId: string;
  /** Reihenfolge der Optionslabels für diese Darstellung. */
  readonly optionsReihenfolge: readonly string[];
  /**
   * Ist die Frage gemerkt?
   *
   * Kommt mit der Sitzung mit, weil die Oberfläche den Stern sonst erst
   * kennt, nachdem die Frage beantwortet wurde: Bis Fassung 0.24.1 begann
   * jede Sitzung mit einer leeren Merkliste, und der Stern stand an jeder
   * Frage auf „nicht gemerkt“ – auch in einer Sitzung mit dem Filter
   * „nur Gemerkte“, in der jede einzelne Frage gemerkt ist.
   */
  readonly gemerkt: boolean;
  /**
   * Was der Lernende bei dieser offenen Frage zuletzt geschrieben hat.
   *
   * Fehlt, wenn es keine offene Frage ist, wenn sie noch nie beantwortet
   * wurde oder wenn das Feld leer blieb – Letzteres ist ausdrücklich erlaubt
   * und soll nicht als Vorhaltung wiederkehren.
   *
   * **Wird erst nach dem Bestätigen gezeigt.** Vorher wäre es eine Vorlage
   * zum Abschreiben und machte aus dem Ausformulieren ein Kopieren.
   *
   * Der Text stand bis Fassung 0.20.0 in `antwort_log.freitext` und wurde von
   * keiner einzigen Abfrage gelesen – geschrieben, aufbewahrt, nie gezeigt.
   */
  readonly letzterFreitext?: LetzterFreitext;
}

/** Eine frühere eigene Antwort, mit dem Tag, an dem sie entstand. */
export interface LetzterFreitext {
  readonly text: string;
  /** Zeitpunkt als ISO-Zeichenkette. */
  readonly zeitpunkt: string;
}
