// @vitest-environment node
/**
 * Die Zahlen im Handbuch gegen den **echten** Katalog.
 *
 * Seit 0.26.4 sagt das Kapitel „Die Lernsitzung“, wie eine frei zu
 * formulierende Antwort gebaut ist – und begründet es mit gezählten
 * Anfangswörtern: 26 Fragen beginnen mit „Was“, 25 mit „Welche“, 7 mit
 * „Wie“, je 5 mit „Wann“ und „Nennen Sie“. Solche Sätze sind Zusagen: Ein
 * neuer Katalogstand verschiebt sie, ohne dass es jemandem auffiele, und
 * dann steht im Handbuch eine Zahl, die niemand mehr nachzählen kann.
 *
 * Deshalb zählt dieser Test sie bei jedem Lauf nach. Er liest die Zahlen aus
 * dem Handbuchtext selbst – nicht aus einer zweiten Liste daneben, die
 * ihrerseits auseinanderlaufen könnte.
 */

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

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

import { HILFE_KAPITEL } from '../src/shared/hilfe';
import type { Katalog } from '../src/shared/katalog';

const wurzel = fileURLToPath(new URL('..', import.meta.url));

const KATALOG = JSON.parse(
  readFileSync(join(wurzel, '..', 'content', 'katalog', 'katalog.json'), 'utf8'),
) as Katalog;

/** Alle Fließtexte des Handbuchs, zu einer Zeichenkette verbunden. */
function handbuchtext(): string {
  return HILFE_KAPITEL.flatMap((kapitel) =>
    kapitel.bloecke.map((block) => {
      if (block.art === 'absatz') return block.text;
      if (block.art === 'liste' || block.art === 'schritte') return block.punkte.join(' ');
      return '';
    }),
  ).join(' ');
}

/** Die offenen Fragen: die ohne Antwortmöglichkeiten. */
function offeneFragen() {
  return KATALOG.fragen.filter((frage) => (frage.optionen ?? []).length === 0);
}

/** Das erste großgeschriebene Wort des Fragetextes. */
function anfangswort(text: string): string {
  return /[A-ZÄÖÜ][a-zäöüß]+/u.exec(text)?.[0] ?? '';
}

describe('Die Zahlen des Handbuchs stimmen mit dem Katalog überein', () => {
  it('nennt so viele offene Fragen, wie der Katalog hat', () => {
    const text = handbuchtext();
    const anzahl = offeneFragen().length;

    expect(text, `Der Katalog hat ${String(anzahl)} offene Fragen.`).toContain(
      `${String(anzahl)} offenen Fragen des Katalogs`,
    );
    expect(text).toContain(`Nur 5 der ${String(anzahl)} Fragen nennen selbst eine Anzahl.`);
  });

  it('zählt die Anfangswörter richtig ab', () => {
    const text = handbuchtext();
    const gezaehlt = new Map<string, number>();
    for (const frage of offeneFragen()) {
      const wort = anfangswort(frage.frage.text);
      gezaehlt.set(wort, (gezaehlt.get(wort) ?? 0) + 1);
    }

    /* Genau die fünf, die der Satz im Handbuch aufzählt. */
    expect(gezaehlt.get('Was')).toBe(26);
    expect(gezaehlt.get('Welche')).toBe(25);
    expect(gezaehlt.get('Wie')).toBe(7);
    expect(gezaehlt.get('Wann')).toBe(5);
    expect(gezaehlt.get('Nennen')).toBe(5);

    expect(text).toContain(
      '26 beginnen mit „Was“, 25 mit „Welche“, 7 mit „Wie“, je 5 mit „Wann“ und „Nennen Sie“',
    );
  });

  it('nennt so viele Fragen mit ausgeschriebener Anzahl, wie es gibt', () => {
    /* „zwei Fälle“, „drei Voraussetzungen“ – ausgeschrieben, nicht als Ziffer. */
    const mitAnzahl = offeneFragen().filter((frage) =>
      /\b(zwei|drei|vier|fünf|sechs)\b/iu.test(frage.frage.text),
    );

    expect(mitAnzahl).toHaveLength(5);
    expect(handbuchtext()).toContain('Nur 5 der');
  });
});
