/**
 * Der Frage-Steckbrief.
 *
 * **Der Anlass.** `FrageStand` transportierte `versuche`, `richtige`,
 * `zuletztBeantwortet`, `faelligAb` und `letzteBewertung` seit jeher über die
 * Brücke – die Oberfläche benutzte davon bis 0.22.0 **ausschließlich**
 * `gemerkt`. Der Lernende konnte nirgends beantworten: Wie oft hatte ich diese
 * Frage schon? Wie oft davon richtig? „Warum kommt die schon wieder?“ blieb
 * ohne Antwort, obwohl sie in der Datenbank stand.
 *
 * Gezeigt wird ausdrücklich der Stand **vor** der heutigen Antwort, und der
 * Text sagt das. Der Stand danach wäre bei offenen Fragen ohnehin nicht zu
 * haben – dort wird die Buchung bis zum Weiterblättern zurückgehalten. Eine
 * Zahl, die je nach Fragetyp etwas anderes bedeutet, wäre schlimmer als keine.
 */

import { render, screen } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';

import { Fragesteckbrief } from '../src/renderer/src/components/lernen/Fragesteckbrief';
import { abstandText } from '../src/renderer/src/lernen/zeitsaetze';
import type { FrageStand } from '../src/shared/lernstand';

function stand(teil: Partial<FrageStand> = {}): FrageStand {
  return {
    frageId: 'I.1-01',
    versuche: 4,
    richtige: 3,
    zuletztBeantwortet: '2026-08-17T09:00:00.000Z',
    faelligAb: '2026-09-04T09:00:00.000Z',
    gemerkt: false,
    letzteBewertung: 'gut',
    ...teil,
  };
}

function bruecke(antwort: FrageStand | Error): void {
  vi.stubGlobal('lernApp', {
    lernFragestand: vi.fn(() =>
      antwort instanceof Error ? Promise.reject(antwort) : Promise.resolve(antwort),
    ),
  });
}

afterEach(() => {
  vi.unstubAllGlobals();
});

describe('Zeitabstand in Worten', () => {
  const jetzt = new Date(2026, 7, 29, 14, 0, 0);

  it('sagt „heute“ und „gestern“', () => {
    expect(abstandText(new Date(2026, 7, 29, 8).toISOString(), jetzt)).toBe('heute');
    expect(abstandText(new Date(2026, 7, 28, 22).toISOString(), jetzt)).toBe('gestern');
  });

  it('rechnet über Kalendertage, nicht über Stunden', () => {
    /* „Gestern“ soll auch dann „gestern“ heißen, wenn dreißig Stunden
       dazwischenliegen – dieselbe Rechnung wie im Anwendungskern. */
    expect(abstandText(new Date(2026, 7, 28, 6).toISOString(), jetzt)).toBe('gestern');
  });

  it('zählt darüber in Tagen', () => {
    expect(abstandText(new Date(2026, 7, 17, 9).toISOString(), jetzt)).toBe('vor 12 Tagen');
  });

  it('kommt mit einer unlesbaren Zeit zurecht', () => {
    expect(abstandText('kein Datum', jetzt)).toBe('');
  });
});

describe('Steckbrief', () => {
  it('nennt Bearbeitungen, Treffer und den letzten Zeitpunkt', async () => {
    bruecke(stand());
    render(<Fragesteckbrief frageId="I.1-01" profilId={1} />);

    expect(await screen.findByText('Diese Frage bisher')).toBeInTheDocument();
    expect(screen.getByText(/4-mal bearbeitet/u)).toBeInTheDocument();
    expect(screen.getByText(/3-mal richtig/u)).toBeInTheDocument();
  });

  it('schweigt bei einer zum ersten Mal vorgelegten Frage', async () => {
    /* Eine Zeile „0-mal bearbeitet, 0-mal richtig“ wäre kein Steckbrief,
       sondern Lärm. */
    bruecke(stand({ versuche: 0, richtige: 0, zuletztBeantwortet: null }));
    const { container } = render(<Fragesteckbrief frageId="I.1-01" profilId={1} />);

    await Promise.resolve();
    expect(container.querySelector('.steckbrief')).toBeNull();
  });

  it('beugt die Einzahl richtig', async () => {
    bruecke(stand({ versuche: 1, richtige: 1 }));
    render(<Fragesteckbrief frageId="I.1-01" profilId={1} />);

    expect(await screen.findByText(/einmal bearbeitet/u)).toBeInTheDocument();
    expect(screen.getByText(/davon einmal richtig/u)).toBeInTheDocument();
  });

  it('bleibt still, wenn der Kanal fehlt', () => {
    /* Der Steckbrief ist eine Zugabe. Eine ältere Fassung des
       Anwendungskerns darf die Sitzung nicht stören. */
    vi.stubGlobal('lernApp', {});
    const { container } = render(<Fragesteckbrief frageId="I.1-01" profilId={1} />);

    expect(container.querySelector('.steckbrief')).toBeNull();
  });

  it('bleibt still, wenn das Lesen scheitert', async () => {
    bruecke(new Error('Datenbank gesperrt'));
    const { container } = render(<Fragesteckbrief frageId="I.1-01" profilId={1} />);

    await Promise.resolve();
    expect(container.querySelector('.steckbrief')).toBeNull();
  });

  it('fragt ohne Lernprofil gar nicht erst', () => {
    bruecke(stand());
    render(<Fragesteckbrief frageId="I.1-01" profilId={null} />);

    expect(
      (globalThis as { lernApp?: { lernFragestand?: unknown } }).lernApp?.lernFragestand,
    ).not.toHaveBeenCalled();
  });
});
