const { test, expect } = require('@playwright/test');

const TEST_EMAIL    = process.env.TEST_EMAIL    || 'lars@stommer.com';
const TEST_PASSWORD = process.env.TEST_PASSWORD || '12345678';

/** Primärer Submit auf der Login-Seite (nicht den Tab "Login" vs. "Registrieren"). */
async function submitLoginForm(page) {
  await page.getByRole('button', { name: 'Anmelden' }).click();
}

async function login(page) {
  await page.goto('/');
  await page.waitForLoadState('networkidle');

  // Warte bis Login-Seite geladen ist
  await page.waitForSelector('input[type="email"]', { timeout: 10000 });

  await page.fill('input[type="email"]', TEST_EMAIL);
  await page.fill('input[type="password"]', TEST_PASSWORD);
  await submitLoginForm(page);
  // Wait until auth is complete: URL leaves /login and Dashboard is rendered
  await page.waitForURL((url) => !url.toString().includes('/login'), { timeout: 15000 });
  await page.waitForLoadState('networkidle');
}

test('1. Login funktioniert', async ({ page }) => {
  await page.goto('/');
  await page.waitForSelector('input[type="email"]', { timeout: 10000 });
  await page.fill('input[type="email"]', TEST_EMAIL);
  await page.fill('input[type="password"]', TEST_PASSWORD);
  await submitLoginForm(page);
  await page.waitForLoadState('networkidle');

  // Nach Login soll der Tab "Login" (Moduswahl) verschwinden — nicht der Submit "Anmelden"
  const loginButton = page.locator('button:has-text("Login")');
  await expect(loginButton).toHaveCount(0, { timeout: 10000 });

  await page.screenshot({ path: 'screenshots/01-nach-login.png' });
  console.log('✓ Login erfolgreich');
});

test('2. Dashboard lädt ohne Fehler', async ({ page }) => {
  await login(page);

  // Warte bis Spinner verschwunden
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  // Dashboard: h1 „Dashboard“ + Begrüßungstext (nicht mehr „Willkommen bei Shinkan“ als Überschrift)
  const main = page.locator('.app-main');
  await expect(main.getByRole('heading', { level: 1, name: 'Dashboard' })).toBeVisible({
    timeout: 5000,
  });
  await expect(main.getByText(/Shinkan unterstützt dich/i)).toBeVisible({ timeout: 5000 });

  await page.screenshot({ path: 'screenshots/02-dashboard.png' });
  console.log('✓ Dashboard OK');
});

test('3. Navigation zu Übungen', async ({ page }) => {
  await login(page);

  // Bei Viewport ≥1024px ist .bottom-nav versteckt — Mobile garantieren wie in playwright.config.js
  await page.setViewportSize({ width: 390, height: 844 });

  // Desktop-Sidebar enthält ebenfalls Übungen – nur Mobile-Bottom-Nav klicken (sichtbarer Link)
  await page.locator('.bottom-nav a[href="/exercises"]').click();
  await page.waitForLoadState('networkidle');

  // Prüfe ob Übungen-Seite geladen
  await expect(page.locator('h1, h2, .page-title')).toContainText(/übungen/i, { timeout: 5000 });

  await page.screenshot({ path: 'screenshots/03-uebungen.png' });
  console.log('✓ Übungen-Seite erreichbar');
});

test('4. Navigation zu Vereine', async ({ page }) => {
  await login(page);
  await page.setViewportSize({ width: 390, height: 844 });

  await page.locator('.bottom-nav a[href="/clubs"]').click();
  await page.waitForLoadState('networkidle');

  // ClubsPage: <h1>Vereinsverwaltung</h1> + Tab <h2>Vereine</h2> → ein kombinierter
  // Selektor löst 2 Treffer aus (Playwright strict mode). URL + primäre Überschrift reichen.
  await expect(page).toHaveURL(/\/clubs\/?$/, { timeout: 5000 });
  await expect(page.getByRole('heading', { level: 1, name: /Vereinsverwaltung/i })).toBeVisible({
    timeout: 5000,
  });

  await page.screenshot({ path: 'screenshots/04-vereine.png' });
  console.log('✓ Vereine-Seite erreichbar');
});

test('5. Desktop-Sidebar sichtbar (Desktop)', async ({ page }) => {
  // Desktop-Viewport
  await page.setViewportSize({ width: 1280, height: 800 });

  await login(page);

  // Prüfe ob Desktop-Sidebar existiert
  const sidebar = page.locator('.desktop-sidebar');
  await expect(sidebar).toBeVisible({ timeout: 5000 });

  await page.screenshot({ path: 'screenshots/05-desktop-sidebar.png' });
  console.log('✓ Desktop-Sidebar sichtbar');
});

test('6. Bottom-Nav sichtbar (Mobile)', async ({ page }) => {
  // Mobile-Viewport
  await page.setViewportSize({ width: 390, height: 844 });

  await login(page);

  // Prüfe ob Bottom-Nav existiert
  const bottomNav = page.locator('.bottom-nav');
  await expect(bottomNav).toBeVisible({ timeout: 5000 });

  await page.screenshot({ path: 'screenshots/06-mobile-bottom-nav.png' });
  console.log('✓ Bottom-Nav sichtbar');
});

test('7. Session-Persistenz nach Reload', async ({ page }) => {
  await login(page);

  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });
  await expect(
    page.locator('.app-main').getByRole('heading', { level: 1, name: 'Dashboard' }),
  ).toBeVisible({ timeout: 10000 });

  await page.reload({ waitUntil: 'domcontentloaded' });
  await page.waitForLoadState('networkidle');

  // Auth lädt erst nach Spinner – nicht auf /login stranden (stabiler als Button „Login“-Tab auf Login-Screen)
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 20000 });
  await expect(page).not.toHaveURL(/\/login(?:\/|$|\?|#)/, { timeout: 20000 });
  await expect(
    page.locator('.app-main').getByRole('heading', { level: 1, name: 'Dashboard' }),
  ).toBeVisible({
    timeout: 20000,
  });

  await page.screenshot({ path: 'screenshots/07-nach-reload.png' });
  console.log('✓ Session bleibt nach Reload erhalten');
});

test('P-12: sessionStorage wird bei Logout bereinigt (sj_coach_* Schlüssel)', async ({ page }) => {
  await page.setViewportSize({ width: 1280, height: 800 });
  await login(page);
  await page.waitForLoadState('networkidle');

  // Coach-Sitzungsdaten simulieren (wie sie TrainingCoachPage schreibt)
  await page.evaluate(() => {
    sessionStorage.setItem('sj_coach_step_42', '3');
    sessionStorage.setItem('sj_coach_deltas_42', '[{"id":1}]');
    sessionStorage.setItem('sj_coach_debrief_42', '0');
    sessionStorage.setItem('fremd_anderer_key', 'muss_erhalten_bleiben');
  });

  const vorLogout = await page.evaluate(() => ({
    step: sessionStorage.getItem('sj_coach_step_42'),
    fremd: sessionStorage.getItem('fremd_anderer_key'),
  }));
  expect(vorLogout.step).toBe('3');
  expect(vorLogout.fremd).toBe('muss_erhalten_bleiben');

  // App.jsx DesktopSidebar-Logout zeigt confirm() — in Playwright headless akzeptieren
  page.once('dialog', dialog => dialog.accept());
  await page.getByRole('button', { name: 'Abmelden' }).click();
  await page.waitForLoadState('networkidle');

  const nachLogout = await page.evaluate(() => ({
    step:    sessionStorage.getItem('sj_coach_step_42'),
    deltas:  sessionStorage.getItem('sj_coach_deltas_42'),
    debrief: sessionStorage.getItem('sj_coach_debrief_42'),
    fremd:   sessionStorage.getItem('fremd_anderer_key'),
    token:   localStorage.getItem('authToken'),
  }));

  expect(nachLogout.step).toBeNull();
  expect(nachLogout.deltas).toBeNull();
  expect(nachLogout.debrief).toBeNull();
  expect(nachLogout.fremd).toBe('muss_erhalten_bleiben');
  expect(nachLogout.token).toBeNull();

  await page.screenshot({ path: 'screenshots/p12-session-storage-nach-logout.png' });
  console.log('✓ P-12: sj_coach_* entfernt, Fremd-Key erhalten, authToken entfernt');
});

// P-01: Rechtstextseiten – öffentliche Routen ohne Auth

const LEGAL_ROUTES = [
  { path: '/impressum', label: 'Impressum' },
  { path: '/datenschutz', label: 'Datenschutz' },
  { path: '/nutzungsbedingungen', label: 'Nutzungsbedingungen' },
  { path: '/medienrichtlinie', label: 'Medienrichtlinie' },
];

for (const route of LEGAL_ROUTES) {
  test(`P-01: ${route.label} ohne Auth erreichbar und enthält Platzhalterhinweis`, async ({ page }) => {
    // Direkt aufrufen ohne Login
    await page.goto(route.path);
    await page.waitForLoadState('networkidle');

    // Seite ist erreichbar (kein Redirect zur Login-Seite)
    expect(page.url()).toContain(route.path);

    // Seitentitel korrekt
    await expect(page.getByRole('heading', { level: 1 })).toContainText(route.label);

    // Platzhalterhinweis sichtbar – nur wenn noch kein echtes Dokument veröffentlicht wurde
    const hasPlaceholder = await page.getByText('MUSTER / PLATZHALTER').first().isVisible().catch(() => false);
    if (hasPlaceholder) {
      console.log(`✓ P-01: ${route.label} – Platzhalter sichtbar`);
    } else {
      console.log(`✓ P-01: ${route.label} – echtes Dokument veröffentlicht (kein Platzhalter)`);
    }

    // Reload funktioniert
    await page.reload();
    await page.waitForLoadState('networkidle');
    expect(page.url()).toContain(route.path);

    console.log(`✓ P-01: ${route.label} – ohne Auth erreichbar, Reload OK`);
  });
}

test('P-01: Login-Seite enthält Links zu allen vier Rechtstextseiten', async ({ page }) => {
  await page.goto('/login');
  await page.waitForLoadState('networkidle');

  for (const route of LEGAL_ROUTES) {
    const link = page.locator(`a[href="${route.path}"]`);
    await expect(link).toBeVisible();
  }

  console.log('✓ P-01: Login-Seite – alle vier Rechtstext-Links vorhanden');
});

// P-01b: Rechtliches über Einstellungen (Mobile/PWA-Erreichbarkeit)

async function gotoAuthenticated(page, path) {
  await page.goto(path);
  await page.waitForLoadState('networkidle');
  // After full-page reload the app re-checks auth from localStorage; wait for spinner to clear
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 15000 });
}

test('P-01b: Einstellungen enthält Link zu Rechtliches', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/settings');
  await expect(page.locator('.app-main').getByRole('heading', { level: 1, name: 'Einstellungen' })).toBeVisible({ timeout: 8000 });

  const link = page.locator('.app-main a[href="/settings/legal"]');
  await expect(link).toBeVisible();

  console.log('✓ P-01b: Einstellungen enthält Link zu /settings/legal');
});

test('P-01b: /settings/legal enthält Links zu allen vier Rechtstextseiten', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/settings/legal');
  await expect(page.locator('.app-main').getByRole('heading', { level: 1, name: 'Rechtliches' })).toBeVisible({ timeout: 8000 });

  for (const route of LEGAL_ROUTES) {
    const link = page.locator(`.app-main a[href="${route.path}"]`);
    await expect(link).toBeVisible();
  }

  console.log('✓ P-01b: /settings/legal – Überschrift + alle vier Rechtstext-Links vorhanden');
});

test('P-01b: Jeder Rechtstext-Link aus /settings/legal führt zur korrekten Route', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  for (const route of LEGAL_ROUTES) {
    await gotoAuthenticated(page, '/settings/legal');
    await expect(page.locator('.app-main').getByRole('heading', { level: 1, name: 'Rechtliches' })).toBeVisible({ timeout: 8000 });

    await page.locator(`.app-main a[href="${route.path}"]`).click();
    await page.waitForLoadState('networkidle');

    expect(page.url()).toContain(route.path);
    await expect(page.getByRole('heading', { level: 1 })).toContainText(route.label);

    console.log(`✓ P-01b: ${route.label} – Link aus /settings/legal korrekt`);
  }
});

// P-01c: Admin-konfigurierbare Rechtstexte

test('P-01c: Rechtstextseiten zeigen Platzhalter-Banner wenn kein published-Dokument', async ({ page }) => {
  // Keine Auth — public route
  await page.goto('/impressum');
  await page.waitForLoadState('networkidle');

  // Seite erreichbar (kein Redirect zu /login)
  expect(page.url()).toContain('/impressum');

  // Spinner weg, dann entweder Platzhalter-Banner oder API-Inhalt (beides OK)
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });
  await expect(page.getByRole('heading', { level: 1 })).toBeVisible({ timeout: 5000 });

  console.log('✓ P-01c: /impressum lädt ohne Fehler (API-fetch mit Fallback)');
});

test('P-01c: /admin/legal-documents erreichbar für Superadmin', async ({ page }) => {
  await page.setViewportSize({ width: 1280, height: 800 });
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/admin/legal-documents');
  // Superadmin sieht die Seite; normaler Admin landet auf 403 (PlatformAdminRoute)
  // Test läuft mit Superadmin-Account (TEST_EMAIL), also Seite sichtbar
  await expect(page.locator('.app-main').getByRole('heading', { level: 1, name: 'Rechtstexte verwalten' })).toBeVisible({ timeout: 8000 });

  await page.screenshot({ path: 'screenshots/p01c-admin-legal-documents.png' });
  console.log('✓ P-01c: /admin/legal-documents erreichbar, Überschrift sichtbar');
});

test('P-01c: Admin-Nav enthält Link zu Rechtstexten', async ({ page }) => {
  await page.setViewportSize({ width: 1280, height: 800 });
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/admin/hierarchy');
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  const link = page.locator('a[href="/admin/legal-documents"]');
  await expect(link).toBeVisible({ timeout: 5000 });

  console.log('✓ P-01c: Admin-Nav enthält Link /admin/legal-documents');
});

// ── P-06: Upload-Einwilligungsdialog ────────────────────────────────────────

test('P-06a: Medienbibliothek lädt ohne Fehler', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/media');
  await expect(page.locator('h1')).toContainText('Medienbibliothek', { timeout: 8000 });

  await page.screenshot({ path: 'screenshots/p06a-media-library.png' });
  console.log('✓ P-06a: Medienbibliothek erreichbar');
});

test('P-06b: Rechte-Dialog erscheint bei Dateiauswahl', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/media');
  await expect(page.locator('h1')).toContainText('Medienbibliothek', { timeout: 8000 });

  // Datei-Upload simulieren (ohne echte Datei – Datei-Input finden und Datei setzen)
  const fileInput = page.locator('input[type="file"]').first();
  await fileInput.setInputFiles({
    name: 'test.png',
    mimeType: 'image/png',
    buffer: Buffer.from('PNG-Testinhalt'),
  });

  // Rechte-Dialog muss erscheinen
  await expect(page.locator('[role="dialog"]')).toBeVisible({ timeout: 5000 });
  await expect(page.locator('[role="dialog"]')).toContainText('Rechte-Erklärung');
  await expect(page.locator('[role="dialog"]')).toContainText('VORLÄUFIG');

  await page.screenshot({ path: 'screenshots/p06b-rights-dialog.png' });
  console.log('✓ P-06b: Rechte-Dialog erscheint bei Dateiauswahl');
});

test('P-06c: Dialog-Abbrechen bricht Upload ab', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/media');
  await expect(page.locator('h1')).toContainText('Medienbibliothek', { timeout: 8000 });

  const fileInput = page.locator('input[type="file"]').first();
  await fileInput.setInputFiles({
    name: 'test.png',
    mimeType: 'image/png',
    buffer: Buffer.from('PNG-Testinhalt'),
  });

  await expect(page.locator('[role="dialog"]')).toBeVisible({ timeout: 5000 });
  await page.locator('[role="dialog"] button:has-text("Abbrechen")').click();

  // Dialog geschlossen, kein Upload-Fortschrittsbalken
  await expect(page.locator('[role="dialog"]')).toHaveCount(0, { timeout: 3000 });

  await page.screenshot({ path: 'screenshots/p06c-dialog-cancel.png' });
  console.log('✓ P-06c: Dialog-Abbrechen schließt Dialog ohne Upload');
});

test('P-06d: Dialog-Bestätigung ohne Pflichtfelder zeigt Fehler', async ({ page }) => {
  await login(page);
  await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });

  await gotoAuthenticated(page, '/media');
  await expect(page.locator('h1')).toContainText('Medienbibliothek', { timeout: 8000 });

  const fileInput = page.locator('input[type="file"]').first();
  await fileInput.setInputFiles({
    name: 'test.png',
    mimeType: 'image/png',
    buffer: Buffer.from('PNG-Testinhalt'),
  });

  await expect(page.locator('[role="dialog"]')).toBeVisible({ timeout: 5000 });
  // Ohne Felder ausfüllen direkt bestätigen
  await page.locator('[role="dialog"] button:has-text("Bestätigen")').click();

  // Fehlermeldung im Dialog
  const dialog = page.locator('[role="dialog"]');
  await expect(dialog).toBeVisible({ timeout: 2000 });
  // Fehlermeldung muss sichtbar sein
  await expect(dialog.locator('p[style*="danger"], p[style*="color: var(--danger)"]')).toBeVisible({ timeout: 2000 });

  await page.screenshot({ path: 'screenshots/p06d-dialog-validation.png' });
  console.log('✓ P-06d: Dialog zeigt Fehler ohne Pflichtfelder');
});

test('P-06e: API-Endpoint /api/admin/media-rights/legacy-summary erreichbar (Superadmin)', async ({ request }) => {
  // Superadmin-Login via API
  const loginRes = await request.post('/api/auth/login', {
    data: { email: TEST_EMAIL, password: TEST_PASSWORD },
  });
  if (!loginRes.ok()) {
    console.log('⚠ P-06e: Login fehlgeschlagen – Test übersprungen');
    return;
  }
  const loginData = await loginRes.json();
  const token = loginData.token;
  if (!token) {
    console.log('⚠ P-06e: Kein Token – Test übersprungen');
    return;
  }

  const res = await request.get('/api/admin/media-rights/legacy-summary', {
    headers: { 'X-Auth-Token': token },
  });

  // Endpoint existiert (200 oder 403 wenn kein Superadmin — aber nicht 404/500)
  expect([200, 403]).toContain(res.status());
  if (res.status() === 200) {
    const data = await res.json();
    expect(data).toHaveProperty('total_active_assets');
    expect(data).toHaveProperty('legacy_unreviewed');
    console.log(`✓ P-06e: Legacy-Summary: ${data.legacy_unreviewed} von ${data.total_active_assets} Medien`);
  } else {
    console.log('✓ P-06e: Endpoint existiert (403 erwartet für Nicht-Superadmin)');
  }
});

test('8. Keine kritischen Console-Fehler', async ({ page }) => {
  const errors = [];
  page.on('console', msg => {
    if (msg.type() === 'error') errors.push(msg.text());
  });

  await login(page);
  await page.waitForLoadState('networkidle');

  // Filtere unkritische Fehler
  const kritisch = errors.filter(e =>
    !e.includes('favicon') &&
    !e.includes('sourceMap') &&
    !e.includes('404') &&
    !e.includes('vite.svg')
  );

  if (kritisch.length > 0) {
    console.log('⚠ Console-Fehler:', kritisch.join(', '));
  } else {
    console.log('✓ Keine kritischen Console-Fehler');
  }

  expect(kritisch.length).toBe(0);
});
