/**
 * „Fehler zu dieser Frage melden“ im echten Fenster.
 *
 * Hier zählt vor allem eines: dass der Text wirklich in der Zwischenablage
 * des Systems landet. Die Oberflächentests prüfen das gegen eine Attrappe;
 * ob Electrons `clipboard` an dieser Stelle tut, was es soll, sagt nur der
 * echte Lauf. Der Weg über `navigator.clipboard` ist hier nachweislich
 * versperrt – siehe `shared/ipc.ts`, Kanal `system:kopieren`.
 */

import { type ElectronApplication, type Page } from '@playwright/test';

import { amStart, appStarten, bauPruefen } from './electron-hilfe';
import { expect, test } from './konsolenwache';

let app: ElectronApplication | undefined;
let fenster: Page;

test.beforeAll(async () => {
  bauPruefen();
  ({ app, fenster } = await appStarten());
});

test.afterAll(async () => {
  await app?.close();
});

test.describe.configure({ mode: 'serial' });

async function zumStart(): Promise<void> {
  for (let i = 0; i < 4; i++) {
    if (await amStart(fenster)) {
      return;
    }
    const zurueck = fenster.getByRole('button', { name: /^(Zum Start|Sitzung beenden)$/u });
    if ((await zurueck.count()) === 0) {
      return;
    }
    await zurueck.first().click();
    await fenster.waitForTimeout(250);
  }
}

async function sitzungOeffnen(): Promise<void> {
  await zumStart();
  await fenster.getByRole('button', { name: /Weiterlernen/u }).click();
  await fenster.getByRole('heading', { level: 1, name: /, Frage \d/u }).waitFor();
}

test.describe('Fehler melden', () => {
  test('legt genau den angezeigten Text in die Zwischenablage', async () => {
    await sitzungOeffnen();

    const aufklapper = fenster.getByText('Fehler zu dieser Frage melden');
    await aufklapper.scrollIntoViewIfNeeded();
    await aufklapper.click();

    const feld = fenster.getByLabel('Meldetext');
    await expect(feld).toBeVisible();
    const angezeigt = await feld.inputValue();
    expect(angezeigt).toContain('Fehlermeldung zur Waffensachkunde-Lernsoftware');
    expect(angezeigt).toContain('Kennung ');

    await fenster.getByRole('button', { name: 'Text kopieren' }).click();
    await expect(fenster.getByText(/liegt in der Zwischenablage/u)).toBeVisible();

    /* Der Kern der Sache: Was in der Zwischenablage des Systems liegt, muss
       zeichengleich mit dem sein, was dastand. */
    const inZwischenablage = await app!.evaluate(({ clipboard }) => clipboard.readText());
    expect(inZwischenablage).toBe(angezeigt);
  });

  test('nennt Fragenkennung, Katalogstand und Fassung', async () => {
    /* Die drei Angaben, ohne die eine Meldung nicht zu bearbeiten ist. Die
       Kennung ist dabei die wichtigere: 227 der 575 Fragen teilen ihre
       amtliche Nummer mit einer anderen. */
    const inhalt = await fenster.getByLabel('Meldetext').inputValue();

    expect(inhalt).toMatch(/Kennung [IVX]+/u);
    expect(inhalt).toContain('Stand 16.12.2024');
    expect(inhalt).toContain('Programm: Fassung ');
  });

  test('verrät nichts über die lernende Person', async () => {
    /* Der Text verlässt später das Gerät. Diese Prüfung läuft am echten
       Profil und am echten Lernstand – anders als der Einheitentest, der
       gegen erfundene Werte prüft. */
    const inhalt = (await fenster.getByLabel('Meldetext').inputValue()).toLowerCase();

    for (const verboten of ['standard', 'appdata', 'sqlite', '.db', 'lernstand von']) {
      expect(inhalt).not.toContain(verboten);
    }
  });

  test('klappt bei der nächsten Frage wieder ein', async () => {
    /* Ein von Hand aufgeklapptes <details> bekommt React nicht wieder zu –
       es vergleicht Eigenschaften mit Eigenschaften, nie mit dem DOM. Der
       Block hängt deshalb an der Identität der Frage: Beim Wechsel entsteht
       ein neues Element, und das ist zu.

       Eigene Sitzung, damit dieser Test nicht davon abhängt, wo der vorige
       aufgehört hat. */
    await sitzungOeffnen();

    const aufklapper = fenster.getByText('Fehler zu dieser Frage melden');
    await aufklapper.scrollIntoViewIfNeeded();
    await aufklapper.click();
    await expect(fenster.getByLabel('Meldetext')).toBeVisible();

    const auswahl = fenster.getByRole('checkbox').or(fenster.getByRole('radio'));
    if ((await auswahl.count()) > 0) {
      await auswahl.first().check();
      await fenster.getByRole('button', { name: /^Antwort bestätigen$/u }).click();
    } else {
      await fenster.getByRole('button', { name: /^Musterantwort anzeigen$/u }).click();
      await fenster.getByRole('button', { name: /^Gewusst$/u }).click();
    }
    await fenster.getByRole('button', { name: /^Nächste Frage$/u }).click();

    /* Am Zustand des <details> selbst gemessen, nicht daran, ob das Feld im
       DOM steht: Ein zugeklapptes <details> behält seine Kinder, es zeigt sie
       nur nicht. Genau diese Feinheit hat den ersten Anlauf dieses Tests
       fälschlich rot gemeldet. */
    await expect(fenster.getByLabel('Meldetext')).toBeHidden();
    expect(
      await fenster
        .locator('details.meldung')
        .evaluate((element) => (element as HTMLDetailsElement).open),
    ).toBe(false);

    await expect(fenster.getByText('Fehler zu dieser Frage melden')).toBeVisible();

    await zumStart();
  });
});
