/**
 * Prüft die Prüfungstermin-Schicht über FSRS.
 *
 * Alles hier ist eigene Entscheidung und nicht durch eine Referenz gedeckt –
 * deshalb wird geprüft, was die Regeln *zusagen*, nicht welche Zahlen gerade
 * herauskommen. Ein Test, der nur die aktuelle Ausgabe festschreibt, würde bei
 * jeder Feinjustierung rot, ohne dass etwas kaputt wäre.
 */

import { describe, expect, it } from 'vitest';

import {
  ANHEBUNG_AB_TAGEN,
  einfuehrungstage,
  lernplanBerechnen,
  machbarkeitFuer,
  MAX_INTERVALL_TAGE,
  SEKUNDEN_PRO_FRAGE_VORGABE,
  SITZUNGSUMFANG,
  VORSCHAU_TAGE,
  wiedervorlageBerechnen,
  zielquoteFuer,
  ZIELQUOTE_GRUND,
  ZIELQUOTE_TERMIN,
  type PlanFrage,
} from '../src/shared/lernplan';
import { abrufwahrscheinlichkeit } from '../src/shared/fsrs';

function frage(teil: Partial<PlanFrage> = {}): PlanFrage {
  /* `bestaetigt: true` als Vorgabe: Diese Datei prüft die Planung, nicht die
     Belegregel. Ohne den Beleg wäre jede Prognose hier null, und die Tests
     prüften nichts mehr. Die Regel selbst steht in `reife.test.ts`. */
  return {
    bereich: 'I.1',
    stabilitaet: null,
    tageSeitAntwort: 0,
    bestaetigt: true,
    faellig: false,
    ...teil,
  };
}

/** `anzahl` gleichartige Fragen – spart Wiederholung in den Fällen unten. */
function fragen(anzahl: number, teil: Partial<PlanFrage> = {}): PlanFrage[] {
  return Array.from({ length: anzahl }, () => frage(teil));
}

describe('Zielquote', () => {
  it('bleibt ohne Termin beim Vorgabewert', () => {
    expect(zielquoteFuer(null)).toBe(ZIELQUOTE_GRUND);
  });

  it('bleibt weit vor dem Termin beim Vorgabewert', () => {
    expect(zielquoteFuer(ANHEBUNG_AB_TAGEN)).toBe(ZIELQUOTE_GRUND);
    expect(zielquoteFuer(ANHEBUNG_AB_TAGEN + 100)).toBe(ZIELQUOTE_GRUND);
  });

  it('erreicht am Prüfungstag die höchste Stufe', () => {
    expect(zielquoteFuer(0)).toBeCloseTo(ZIELQUOTE_TERMIN, 10);
  });

  it('steigt dazwischen streng monoton', () => {
    let vorher = zielquoteFuer(ANHEBUNG_AB_TAGEN);
    for (let tage = ANHEBUNG_AB_TAGEN - 1; tage >= 0; tage -= 1) {
      const jetzt = zielquoteFuer(tage);
      expect(jetzt).toBeGreaterThan(vorher);
      vorher = jetzt;
    }
  });

  it('bleibt nach einem verstrichenen Termin oben', () => {
    // Wer den Termin verpasst hat, lernt vermutlich für einen Nachholtermin.
    // Die Quote darf dann nicht auf den Ruhewert zurückfallen.
    expect(zielquoteFuer(-1)).toBeCloseTo(ZIELQUOTE_TERMIN, 10);
    expect(zielquoteFuer(-90)).toBeCloseTo(ZIELQUOTE_TERMIN, 10);
  });
});

describe('Wiedervorlage', () => {
  it('macht eine Frage bei „nochmal“ sofort wieder fällig', () => {
    expect(wiedervorlageBerechnen(null, 1, 0, null).intervallTage).toBe(0);
    expect(
      wiedervorlageBerechnen({ stabilitaet: 200, schwierigkeit: 2 }, 1, 30, null).intervallTage,
    ).toBe(0);
  });

  it('schreibt den Gedächtnisstand auch bei „nochmal“ fort', () => {
    // Intervall 0 ist eine Entscheidung der Oberfläche, kein Zurücksetzen des
    // Modells. Sonst ginge die Historie der Frage verloren.
    const vorher = { stabilitaet: 40, schwierigkeit: 3 };
    const nachher = wiedervorlageBerechnen(vorher, 1, 30, null);

    expect(nachher.stabilitaet).toBeGreaterThan(0);
    expect(nachher.stabilitaet).toBeLessThan(vorher.stabilitaet);
    expect(nachher.schwierigkeit).toBeGreaterThan(vorher.schwierigkeit);
  });

  it('vergibt sonst nie weniger als einen Tag', () => {
    for (const grad of [2, 3, 4] as const) {
      expect(wiedervorlageBerechnen(null, grad, 0, null).intervallTage).toBeGreaterThanOrEqual(1);
    }
  });

  it('überschreitet die Obergrenze nicht', () => {
    const fest = { stabilitaet: 100_000, schwierigkeit: 1 };
    expect(wiedervorlageBerechnen(fest, 4, 10, null).intervallTage).toBe(MAX_INTERVALL_TAGE);
  });

  it('verkürzt sich, je näher der Termin rückt', () => {
    const stand = { stabilitaet: 60, schwierigkeit: 5 };
    const weit = wiedervorlageBerechnen(stand, 3, 60, 200).intervallTage;
    const mittel = wiedervorlageBerechnen(stand, 3, 60, 14).intervallTage;
    const nah = wiedervorlageBerechnen(stand, 3, 60, 2).intervallTage;

    expect(mittel).toBeLessThan(weit);
    expect(nah).toBeLessThan(mittel);
  });

  it('lässt den Gedächtnisstand vom Termin unberührt', () => {
    // Der Termin darf nur den Vorlagerhythmus ändern, nicht das Modell –
    // sonst würde eine Terminänderung die gemessene Gedächtnisleistung
    // rückwirkend verfälschen.
    const stand = { stabilitaet: 20, schwierigkeit: 4 };
    const ohne = wiedervorlageBerechnen(stand, 3, 20, null);
    const mit = wiedervorlageBerechnen(stand, 3, 20, 3);

    expect(mit.stabilitaet).toBe(ohne.stabilitaet);
    expect(mit.schwierigkeit).toBe(ohne.schwierigkeit);
  });
});

describe('Einführungstage', () => {
  it('lässt bei langer Vorbereitung fast alle Tage übrig', () => {
    expect(einfuehrungstage(100)).toBe(97);
  });

  it('behält bei sehr kurzer Vorbereitung mindestens einen Tag', () => {
    expect(einfuehrungstage(0)).toBe(1);
    expect(einfuehrungstage(1)).toBe(1);
    expect(einfuehrungstage(2)).toBe(2);
  });

  it('nimmt nie mehr als den Puffer weg', () => {
    for (let tage = 0; tage <= 400; tage += 1) {
      const uebrig = einfuehrungstage(tage);
      expect(uebrig).toBeGreaterThanOrEqual(1);
      expect(uebrig).toBeLessThanOrEqual(Math.max(1, tage));
      expect(tage - uebrig).toBeLessThanOrEqual(3);
    }
  });
});

describe('Machbarkeit', () => {
  it('meldet fehlenden Termin gesondert', () => {
    expect(machbarkeitFuer(0, null)).toBe('kein_termin');
    expect(machbarkeitFuer(500, null)).toBe('kein_termin');
  });

  it('meldet einen verstrichenen Termin gesondert', () => {
    expect(machbarkeitFuer(10, -1)).toBe('termin_vorbei');
  });

  it('stuft nach Tagesaufwand ab', () => {
    expect(machbarkeitFuer(10, 30)).toBe('entspannt');
    expect(machbarkeitFuer(30, 30)).toBe('machbar');
    expect(machbarkeitFuer(60, 30)).toBe('knapp');
    expect(machbarkeitFuer(200, 30)).toBe('zu_wenig_zeit');
  });

  it('wird mit steigendem Aufwand nie günstiger', () => {
    const rang = ['entspannt', 'machbar', 'knapp', 'zu_wenig_zeit'];
    let bisher = -1;
    for (let minuten = 0; minuten <= 300; minuten += 1) {
      const stufe = rang.indexOf(machbarkeitFuer(minuten, 30));
      expect(stufe).toBeGreaterThanOrEqual(bisher);
      bisher = stufe;
    }
  });
});

describe('Lernplan', () => {
  it('zählt nie beantwortete Fragen und Fällige getrennt', () => {
    const plan = lernplanBerechnen({
      termin: '2026-09-01',
      tageBisTermin: 30,
      fragen: [
        ...fragen(10),
        ...fragen(5, { stabilitaet: 10, tageSeitAntwort: 12, faellig: true }),
        ...fragen(3, { stabilitaet: 10, tageSeitAntwort: 1, faellig: false }),
      ],
      sekundenProFrage: null,
    });

    expect(plan.gesamtFragen).toBe(18);
    expect(plan.nieBeantwortet).toBe(10);
    expect(plan.faellig).toBe(5);
  });

  it('wertet eine nie beantwortete Frage als nicht gekonnt', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: fragen(100),
      sekundenProFrage: null,
    });

    expect(plan.prognoseHeute).toBe(0);
  });

  it('meldet auch bei eben beantwortetem Katalog nie volle Prognose', () => {
    /*
      Dieser Test hat bis Fassung 0.11.0 das Gegenteil verlangt – er prüfte
      auf „fast genau 1“ und schrieb damit eine Unwahrheit fest:
      `abrufwahrscheinlichkeit(S, 0)` ist für JEDES S exakt 1, auch für eine
      Frage, die eben erst zum ersten Mal aufgetaucht ist. Während einer
      Sitzung wanderte die Prognose deshalb gegen 100 Prozent, und zwar
      unabhängig davon, wie gut jemand geantwortet hatte.

      Seit `reife.ts` wird nie mit weniger als einem Tag Abstand gerechnet.
      Der Wert bleibt hoch – 30 Tage Stabilität sind viel –, aber er ist
      keine Zusage mehr.
    */
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: fragen(50, { stabilitaet: 30, tageSeitAntwort: 0 }),
      sekundenProFrage: null,
    });

    expect(plan.prognoseHeute).toBeLessThan(1);
    expect(plan.prognoseHeute).toBeCloseTo(abrufwahrscheinlichkeit(30, 1), 10);
  });

  it('zeigt in der Prognose zum Termin, was Nichtstun kostet', () => {
    const plan = lernplanBerechnen({
      termin: '2026-04-01',
      tageBisTermin: 40,
      fragen: fragen(50, { stabilitaet: 20, tageSeitAntwort: 0 }),
      sekundenProFrage: null,
    });

    expect(plan.prognoseAmTermin).not.toBeNull();
    expect(plan.prognoseAmTermin!).toBeLessThan(plan.prognoseHeute);
  });

  it('lässt die Prognose zum Termin ohne Termin offen', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: fragen(10, { stabilitaet: 5, tageSeitAntwort: 1 }),
      sekundenProFrage: null,
    });

    expect(plan.prognoseAmTermin).toBeNull();
  });

  it('verteilt neue Fragen über die verbleibende Zeit', () => {
    const plan = lernplanBerechnen({
      termin: '2026-04-01',
      tageBisTermin: 40,
      fragen: fragen(370),
      sekundenProFrage: null,
    });

    // 370 Fragen auf 37 Einführungstage.
    expect(plan.pensum.neu).toBe(10);
    expect(plan.pensum.wiederholung).toBe(0);
    expect(plan.pensum.gesamt).toBe(10);
  });

  it('verlangt bei knapper Zeit mehr pro Tag', () => {
    const wenige = lernplanBerechnen({
      termin: '2026-04-01',
      tageBisTermin: 5,
      fragen: fragen(575),
      sekundenProFrage: null,
    });
    const viele = lernplanBerechnen({
      termin: '2026-09-01',
      tageBisTermin: 180,
      fragen: fragen(575),
      sekundenProFrage: null,
    });

    // 575 Fragen auf vier Einführungstage sind rund eine Stunde am Tag –
    // anstrengend, aber machbar. Erst darunter wird es unrealistisch.
    expect(wenige.pensum.neu).toBeGreaterThan(viele.pensum.neu);
    expect(wenige.machbarkeit).toBe('knapp');
    expect(viele.machbarkeit).toBe('entspannt');
  });

  it('sagt deutlich, wenn die Zeit nicht mehr reicht', () => {
    const plan = lernplanBerechnen({
      termin: '2026-03-03',
      tageBisTermin: 2,
      fragen: fragen(575),
      sekundenProFrage: null,
    });

    expect(plan.pensum.minuten).toBeGreaterThan(90);
    expect(plan.machbarkeit).toBe('zu_wenig_zeit');
  });

  it('verlangt nie mehr neue Fragen, als es überhaupt gibt', () => {
    const plan = lernplanBerechnen({
      termin: '2026-03-02',
      tageBisTermin: 1,
      fragen: fragen(5),
      sekundenProFrage: null,
    });

    expect(plan.pensum.neu).toBe(5);
  });

  it('schlägt ohne Termin eine Sitzung vor', () => {
    /* Ohne Stichtag gibt es nichts zu verteilen. „Nichts zu tun“ wäre aber
       falsch, solange der halbe Katalog ungesehen ist – deshalb ein
       Vorschlag in der Größe einer Lernsitzung. */
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: fragen(575),
      sekundenProFrage: null,
    });

    expect(plan.pensum.neu).toBe(SITZUNGSUMFANG);
    expect(plan.machbarkeit).toBe('kein_termin');
  });

  it('meldet ohne Termin nichts zu tun, wenn alles beantwortet ist', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: fragen(575, { stabilitaet: 30, tageSeitAntwort: 1 }),
      sekundenProFrage: null,
    });

    expect(plan.pensum.gesamt).toBe(0);
  });

  it('rechnet die Dauer mit dem eigenen Tempo, wenn eines vorliegt', () => {
    const daten = {
      termin: '2026-04-01',
      tageBisTermin: 10,
      fragen: fragen(60, { stabilitaet: 1, tageSeitAntwort: 5, faellig: true }),
    };

    const schnell = lernplanBerechnen({ ...daten, sekundenProFrage: 10 });
    const langsam = lernplanBerechnen({ ...daten, sekundenProFrage: 40 });

    expect(schnell.pensum.minuten).toBe(10);
    expect(langsam.pensum.minuten).toBe(40);
    expect(schnell.sekundenProFrage).toBe(10);
  });

  it('greift ohne eigenes Tempo auf den Vorgabewert zurück', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: fragen(1),
      sekundenProFrage: null,
    });

    expect(plan.sekundenProFrage).toBe(SEKUNDEN_PRO_FRAGE_VORGABE);
  });

  it('weist ein unsinniges Tempo ab, statt damit zu rechnen', () => {
    for (const tempo of [0, -5]) {
      const plan = lernplanBerechnen({
        termin: null,
        tageBisTermin: null,
        fragen: fragen(1),
        sekundenProFrage: tempo,
      });
      expect(plan.sekundenProFrage).toBe(SEKUNDEN_PRO_FRAGE_VORGABE);
    }
  });

  it('kommt mit einem leeren Katalog zurecht', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      fragen: [],
      sekundenProFrage: null,
    });

    expect(plan.gesamtFragen).toBe(0);
    expect(plan.prognoseHeute).toBe(0);
    expect(plan.pensum.gesamt).toBe(0);
  });

  it('führt nach dem Termin keine neuen Fragen mehr ein', () => {
    const plan = lernplanBerechnen({
      termin: '2026-01-01',
      tageBisTermin: -30,
      fragen: fragen(100),
      sekundenProFrage: null,
    });

    expect(plan.pensum.neu).toBe(0);
    expect(plan.prognoseAmTermin).toBeNull();
    expect(plan.machbarkeit).toBe('termin_vorbei');
  });
});

/*
  Die Arbeitslast-Vorschau.

  Der Plan kannte bis 0.22.0 nur „heute“. Weil die Zielquote ab
  ANHEBUNG_AB_TAGEN Tagen vor dem Termin steigt und die Intervalle dadurch
  zusammenrücken, türmt sich ein Wiederholungsberg, den der Lernende erst am
  jeweiligen Morgen erfuhr.

  Was hier geprüft wird, ist vor allem die **Ehrlichkeit** der Zahl: Sie ist
  eine Untergrenze und darf nichts enthalten, was noch gar keinen Termin hat.
*/
describe('Arbeitslast-Vorschau', () => {
  it('zählt die Wiederholungen je Tag', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      sekundenProFrage: null,
      fragen: [
        ...fragen(3, { stabilitaet: 5, faelligInTagen: 0, faellig: true }),
        ...fragen(2, { stabilitaet: 5, faelligInTagen: 1 }),
        ...fragen(7, { stabilitaet: 5, faelligInTagen: 4 }),
      ],
    });

    expect(plan.vorschau?.[0]).toBe(3);
    expect(plan.vorschau?.[1]).toBe(2);
    expect(plan.vorschau?.[4]).toBe(7);
    expect(plan.vorschau?.[2]).toBe(0);
  });

  it('lässt nie beantwortete Fragen draußen', () => {
    /* Sie haben keinen Termin, sondern kommen mit der Einführungsrate — eine
       eigene, planbare Größe. Sie hier mitzuzählen machte aus der
       Bestandsauskunft eine Vermutung. */
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      sekundenProFrage: null,
      fragen: fragen(20, { stabilitaet: null, faelligInTagen: null }),
    });

    expect(plan.vorschau?.every((anzahl) => anzahl === 0)).toBe(true);
  });

  it('reicht nie über den Prüfungstermin hinaus', () => {
    /* Eine Vorschau auf Tage nach der Prüfung wäre eine Auskunft ohne
       Adressaten. */
    const plan = lernplanBerechnen({
      termin: '2026-03-05',
      tageBisTermin: 3,
      sekundenProFrage: null,
      fragen: fragen(5, { stabilitaet: 5, faelligInTagen: 9 }),
    });

    expect(plan.vorschau).toHaveLength(4);
    expect(plan.vorschau?.every((anzahl) => anzahl === 0)).toBe(true);
  });

  it('reicht ohne Termin bis zur festen Weite', () => {
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      sekundenProFrage: null,
      fragen: fragen(1, { stabilitaet: 5, faelligInTagen: 0, faellig: true }),
    });

    expect(plan.vorschau).toHaveLength(VORSCHAU_TAGE + 1);
  });

  it('kommt ohne die neue Angabe zurecht', () => {
    /* Ein Lernstand einer älteren Fassung liefert `faelligInTagen` nicht.
       Das darf die Planung nicht zu Fall bringen. */
    const plan = lernplanBerechnen({
      termin: null,
      tageBisTermin: null,
      sekundenProFrage: null,
      fragen: fragen(4, { stabilitaet: 5, faellig: true }),
    });

    expect(plan.vorschau?.every((anzahl) => anzahl === 0)).toBe(true);
  });
});

describe('Der Prüfungstag', () => {
  it('verlangt keine neuen Fragen mehr', () => {
    /*
      Der Grund ist keine Schonung, sondern eine Ableitung aus der Belegregel:
      Eine Frage, die heute zum ersten Mal auftaucht, kann nicht mehr belegt
      werden – dafür bräuchte es eine richtige Antwort nach mindestens einem
      Tag Abstand, und diesen Tag gibt es nicht mehr.

      Vorher stand hier `< 0`. Da `einfuehrungstage(0)` auf 1 zurückfällt,
      ergab das den ganzen Rest: 300 ungesehene Fragen und 20 fällige wurden
      am Morgen der Prüfung zu „Heute 320 Fragen, etwa 133 Minuten“.
    */
    const plan = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 0,
      fragen: [
        ...fragen(300),
        ...fragen(20, { stabilitaet: 5, tageSeitAntwort: 9, faellig: true }),
      ],
      sekundenProFrage: null,
    });

    expect(plan.pensum.neu).toBe(0);
    expect(plan.pensum.wiederholung).toBe(20);
    expect(plan.pensum.gesamt).toBe(20);
  });

  it('lässt den Vortag unberührt', () => {
    /* Dort ist der Beleg noch erreichbar, und mehr Tage gibt es nicht. Der
       Randfall gehört benannt, nicht behoben – ein harter Einführungsstopp
       über mehrere Tage verstecke ungesehene Fragen ganz. */
    const plan = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 1,
      fragen: fragen(300),
      sekundenProFrage: null,
    });

    expect(plan.pensum.neu).toBeGreaterThan(0);
  });
});

describe('Was bewusst nicht gebaut ist', () => {
  /*
    Diese Prüfungen halten Ablehnungen fest, die in
    `docs/entscheidung-lernphasen.md` begründet sind. Ohne sie wäre jede
    Ablehnung nur ein Kommentar – und Kommentare überschreibt irgendwann
    jemand, der PLAN.md liest und die Zusage darin findet.
  */
  it('deckelt Wiedervorlagen nicht am Prüfungstermin', () => {
    /*
      Jede geprüfte Kappung schiebt alles, was über den Termin hinausginge,
      auf den Prüfungstag selbst – gemessen 432 von 486 Fragen an einem Tag,
      rund drei Stunden. Und sie senkt den Reifegrad, weil in dieser Anwendung
      eine überflüssige Wiederholung nicht nur Zeit kostet: Eine falsche
      Antwort nimmt den Beleg weg.
    */
    const stand = { stabilitaet: 60, schwierigkeit: 5 };
    const vorlage = wiedervorlageBerechnen(stand, 3, 1, 10);

    expect(vorlage.intervallTage).toBeGreaterThan(10);
  });

  it('kennt keinen Phasenbegriff im Lernplan', () => {
    /*
      Phase 1 wäre die Belegregel aus `reife.ts`, Phase 2 die Definition des
      FSRS-Intervalls, Phase 3 rechnet der Plan von selbst nach, und Phase 4
      wäre ein Etikett über `ANHEBUNG_AB_TAGEN`. Vier Namen für Dinge, die es
      gibt oder die nichts ändern.
    */
    const plan = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 30,
      fragen: fragen(100),
      sekundenProFrage: null,
    });

    expect(Object.keys(plan)).not.toContain('phase');
    expect(Object.keys(plan)).not.toContain('rueckstand');
  });

  it('holt ausgelassene Tage von selbst auf', () => {
    /*
      Die Zusage „Rückstand erhöht das Tagespensum statt still zu
      verschieben“ ist durch die Bauart bereits erfüllt: Die Rate ergibt sich
      täglich neu aus den ungesehenen Fragen und den Resttagen. Wer Tage
      auslässt, bekommt danach mehr – ohne dass irgendwo „Rückstand“ stünde.

      Gemessen wird mit zehn ausgelassenen Tagen und nicht mit dreien: Bei 40
      Tagen Rest ändern drei Tage die Rate gar nicht (9 bleibt 9). Das ist
      keine Schwäche, sondern der eigentliche Grund gegen einen
      Rückstandsbegriff – der Plan schluckt kleine Lücken, und eine Anzeige,
      die sie benennte, machte aus Nichts eine Mahnung.
    */
    const ungesehen = 300;
    const vorher = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 20,
      fragen: fragen(ungesehen),
      sekundenProFrage: null,
    });
    const nachZehnTagenNichtstun = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 10,
      fragen: fragen(ungesehen),
      sekundenProFrage: null,
    });

    expect(nachZehnTagenNichtstun.pensum.neu).toBeGreaterThan(vorher.pensum.neu);
  });

  it('lässt drei ausgelassene Tage bei viel Vorlauf gar nicht auffallen', () => {
    /* Genau deshalb gibt es keinen Rückstandsbegriff: Es gibt nichts zu
       melden. */
    const bei40 = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 40,
      fragen: fragen(300),
      sekundenProFrage: null,
    });
    const bei37 = lernplanBerechnen({
      termin: '2026-06-15',
      tageBisTermin: 37,
      fragen: fragen(300),
      sekundenProFrage: null,
    });

    expect(bei37.pensum.neu).toBe(bei40.pensum.neu);
  });
});
