/**
 * Die Prüfliste zur Selbstbewertung offener Fragen.
 *
 * **Der Anlass.** Bei 63 der 104 offenen Fragen ist in der amtlichen
 * Musterantwort nichts unterstrichen, und die Anwendung gibt die
 * Unterstreichungen seit 0.17.0 zu Recht nicht mehr als Pflichtinhalt aus.
 * Damit stand der Lernende bei der vierstufigen Selbstbewertung – die
 * unmittelbar die Wiedervorlage steuert – ohne jedes Kriterium da.
 *
 * **Die Leitplanke.** `docs/entscheidung-freitext.md` Abschnitt 8 verlangt,
 * dass über einer solchen Liste **nie wieder** „muss Ihre Antwort enthalten“
 * steht. Der letzte Test dieser Datei hält das am ganzen Bestand fest.
 */

import { readFileSync } from 'node:fs';
import { join } from 'node:path';

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

import type { Erklaerungen } from '../src/shared/erklaerungen';
import type { Katalog } from '../src/shared/katalog';

const WURZEL = join(process.cwd(), '..');
const ERKLAERUNGEN = JSON.parse(
  readFileSync(join(WURZEL, 'content', 'erklaerungen.json'), 'utf8'),
) as Erklaerungen;
const KATALOG = JSON.parse(
  readFileSync(join(WURZEL, 'content', 'katalog', 'katalog.json'), 'utf8'),
) as Katalog;

const OFFEN = new Set(KATALOG.fragen.filter((frage) => frage.typ !== 'mc').map((f) => f.id));
const MIT_PUNKTEN = Object.entries(ERKLAERUNGEN.zuFrage).filter(
  ([, eintrag]) => eintrag.kernpunkte !== undefined,
);

describe('Die ausgelieferten Kernpunkte', () => {
  it('decken den größeren Teil der offenen Fragen ab', () => {
    /* Nicht alle: Wo die Musterantwort aus einer einzigen Tatsache besteht
       („Unbefristet“, „Nein“), wäre eine Prüfliste mit einem Punkt kein
       Werkzeug, sondern Beiwerk. */
    expect(OFFEN.size).toBe(104);
    expect(MIT_PUNKTEN.length).toBeGreaterThan(70);
    expect(MIT_PUNKTEN.length).toBeLessThanOrEqual(OFFEN.size);
  });

  it('stehen ausschließlich an offenen Fragen', () => {
    /* Bei einer Auswahlfrage stehen die Antwortmöglichkeiten schon da – eine
       Prüfliste wäre dort die Lösung, nicht eine Hilfe beim Bewerten. */
    const falschePlatzierung = MIT_PUNKTEN.filter(([frageId]) => !OFFEN.has(frageId)).map(
      ([frageId]) => frageId,
    );

    expect(falschePlatzierung).toEqual([]);
  });

  it('führen zwischen zwei und acht Punkte', () => {
    const daneben = MIT_PUNKTEN.filter(([, eintrag]) => {
      const anzahl = eintrag.kernpunkte?.length ?? 0;
      return anzahl < 2 || anzahl > 8;
    }).map(([frageId]) => frageId);

    expect(daneben).toEqual([]);
  });

  it('wiederholen keinen Punkt innerhalb einer Frage', () => {
    const doppelt = MIT_PUNKTEN.filter(([, eintrag]) => {
      const punkte = eintrag.kernpunkte ?? [];
      return new Set(punkte).size !== punkte.length;
    }).map(([frageId]) => frageId);

    expect(doppelt).toEqual([]);
  });

  it('bleiben Stichworte statt Satzgefüge', () => {
    const zuLang = MIT_PUNKTEN.flatMap(([frageId, eintrag]) =>
      (eintrag.kernpunkte ?? [])
        .filter((punkt) => punkt.length > 140 || punkt.trim().length === 0)
        .map((punkt) => `${frageId}: ${punkt.slice(0, 40)}`),
    );

    expect(zuLang).toEqual([]);
  });

  it('behaupten nirgends, was eine Antwort enthalten muss', () => {
    /* Die Leitplanke aus `docs/entscheidung-freitext.md` Abschnitt 8. Bis
       Fassung 0.17.0 stand über einer ähnlichen Liste „Diese Kernelemente muss
       Ihre Antwort enthalten“ – unbelegt, und ausdrücklich abgeschafft. Dieser
       Test hält fest, dass die Behauptung nicht durch die Hintertür
       zurückkommt. */
    const verboten = /muss\s+(ihre|die)\s+antwort|zwingend\s+erforderlich/iu;
    const verstoesse = MIT_PUNKTEN.flatMap(([frageId, eintrag]) =>
      (eintrag.kernpunkte ?? []).filter((punkt) => verboten.test(punkt)).map(() => frageId),
    );

    expect(verstoesse).toEqual([]);
  });

  it('sind bei den Fragen gesetzt, an denen der Befund hing', () => {
    // Vier Beispiele quer durch die Kapitel, damit ein stilles Verschwinden
    // auffällt.
    expect(ERKLAERUNGEN.zuFrage['I.5-02']?.kernpunkte).toContain(
      'gegen einen gegenwärtigen rechtswidrigen Angriff',
    );
    expect(ERKLAERUNGEN.zuFrage['I.1-30']?.kernpunkte).toHaveLength(4);
    expect(ERKLAERUNGEN.zuFrage['II-20']?.kernpunkte).toEqual([
      'Hülse',
      'Geschoss',
      'Zündsatz',
      'Treibladung',
    ]);
    expect(ERKLAERUNGEN.zuFrage['IV-41']?.kernpunkte).toHaveLength(6);
  });

  it('lassen die einteiligen Musterantworten aus', () => {
    /* Beispiele: „Unbefristet“, „Ja“, „Mindestens alle drei Jahre“. Eine
       Prüfliste mit einem Punkt wäre Beiwerk. */
    for (const frageId of ['I.1-71', 'I.1-72', 'I.1-65']) {
      expect(ERKLAERUNGEN.zuFrage[frageId]?.kernpunkte, frageId).toBeUndefined();
    }
  });
});
