/**
 * Authentication Setup for Playwright Tests
 *
 * This file handles authentication once and saves the session state
 * so subsequent tests can reuse it without logging in again.
 * This prevents rate limiting issues from multiple login attempts.
 */

import { test as setup, expect } from '@playwright/test';
import { mkdirSync } from 'fs';
import path from 'path';

// Fallbacks for convenience — these are non-sensitive test-only defaults that
// match the dev/CI fixture credentials, so developers can run the suite without
// extra setup.  Override via env vars when pointing at a different test server.
const TEST_USERNAME = process.env.TEST_USERNAME || 'test_admin';
const TEST_PASSWORD = process.env.TEST_PASSWORD || 'testpass123';

const authDir = path.join(__dirname, '../.auth');
const authFile = path.join(authDir, 'user.json');

// Ensure .auth directory exists before storageState() call
mkdirSync(authDir, { recursive: true });

setup('authenticate', async ({ page }) => {
  // Navigate to login page
  await page.goto('/auth/login');

  // Fill in credentials
  await page.fill('input[name="username"]', TEST_USERNAME);
  await page.fill('input[name="password"]', TEST_PASSWORD);

  // Submit the form and capture the server's response to the login POST.
  // On success the handler returns a 302 redirect to '/'; a login *failure*
  // re-renders the page with an explicit error status (401 bad credentials /
  // unregistered user, 429 lockout, 503 DB-init failure). Asserting that
  // status here makes those login failures fail fast (~1s) with a named
  // cause instead of the opaque waitForURL('/') timeout below — e.g. the
  // SQLCipher KDF mismatch fixed in PR #4775 only ever surfaced as a 30s
  // navigation hang. (A post-302 hang — slow/broken index, missing session —
  // is still caught by the waitForURL / .ldr-user-info checks, just less
  // specifically; this assertion only covers the login-response subset.)
  const [loginResponse] = await Promise.all([
    page.waitForResponse(
      (r) =>
        r.url().includes('/auth/login') && r.request().method() === 'POST',
    ),
    page.click('button[type="submit"]'),
  ]);

  const status = loginResponse.status();
  if (status >= 400) {
    // Keep the remediation pointer durable: name the symptom and point at the
    // workflow's KDF note rather than re-listing env-var names here (those were
    // already renamed once in #4558 and would rot in two places).
    throw new Error(
      `Login failed for "${TEST_USERNAME}": POST /auth/login returned HTTP ${status}. ` +
        'A 401 means the credentials were rejected — wrong password, an ' +
        'unregistered user (no encrypted DB), or a SQLCipher KDF/cipher ' +
        'mismatch between the DB-init step and the server step (see the KDF ' +
        'note in .github/workflows/playwright-webkit-tests.yml and PR #4775). ' +
        'A 429 means the account is locked; a 503 means the server could not ' +
        'initialise the database.',
    );
  }

  // Wait for navigation to complete (authentication successful)
  await page.waitForURL('/', { timeout: 60000 });

  // Verify we're logged in by checking for user info display
  await expect(page.locator('.ldr-user-info')).toBeVisible();

  // Save the authentication state
  await page.context().storageState({ path: authFile });
});
