// Playwright E2E / visual-regression / a11y harness for BillTracker.
// See docs/QA_PLAN.md §4.4 and the B-UI / B14 / B15 batches.
//
// Setup (one-time):  npm install  &&  npx playwright install chromium
// Run:               npm run test:e2e         (headless)
//                    npm run test:e2e:ui      (watch/debug)
//                    npm run test:e2e:update  (re-baseline screenshots)
//
// SAFETY: the two `webServer` entries boot the app against a SCRATCH DB
// (e2e/setup/prepare-db.js seeds it) on DEDICATED ports (5199 UI / 3099 API), so
// E2E never touches your real db/bills.db and never reuses a dev server running
// on 5173/3000. `reuseExistingServer` is false for the same reason.
const { defineConfig, devices } = require('@playwright/test');
const { scratchDbPath, API_PORT, UI_PORT } = require('./e2e/constants');

const baseURL = `http://localhost:${UI_PORT}`;

module.exports = defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [['list'], ['html', { open: 'never' }]],

  use: {
    baseURL,
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },

  // Visual-regression tolerance. Screenshots are OS/font-sensitive, so baselines
  // are committed per-platform (Playwright suffixes them with the platform).
  expect: {
    toHaveScreenshot: { maxDiffPixelRatio: 0.02, animations: 'disabled' },
  },

  projects: [
    // Logs in once and writes STORAGE_STATE; browser projects depend on it.
    { name: 'setup', testMatch: /auth\.setup\.js/ },

    {
      name: 'chromium-desktop',
      use: { ...devices['Desktop Chrome'] },
      dependencies: ['setup'],
      testIgnore: [/auth\.setup\.js/, /api\.probe\.spec\.js/, /a11y\.authed\.spec\.js/],
    },
    {
      name: 'chromium-mobile',
      use: { ...devices['Pixel 5'] },
      dependencies: ['setup'],
      testIgnore: [/auth\.setup\.js/, /api\.probe\.spec\.js/, /a11y\.authed\.spec\.js/],
    },
    // Find-mode diagnostics (adversarial API probe + authenticated a11y scan).
    // Own project so they don't run concurrently with / pollute the UI specs, and
    // so open findings here don't turn the default suite red. Run on demand:
    // `npm run test:e2e:probe`. Fold a spec into the default projects once its
    // findings are fixed (it becomes a passing regression guard).
    {
      name: 'probe',
      testMatch: /(api\.probe|a11y\.authed)\.spec\.js/,
      use: { ...devices['Desktop Chrome'] },
      dependencies: ['setup'],
    },
    // Cross-browser (WebAuthn/Select behavior differs) — enable when ready:
    // { name: 'firefox', use: { ...devices['Desktop Firefox'] }, dependencies: ['setup'], testIgnore: /auth\.setup\.js/ },
    // { name: 'webkit',  use: { ...devices['Desktop Safari'] },  dependencies: ['setup'], testIgnore: /auth\.setup\.js/ },
  ],

  // Two servers: the API (node) and the Vite UI that proxies /api to it. Both
  // run against the scratch DB on dedicated ports. Playwright waits for each
  // `url` to respond before starting tests.
  webServer: [
    {
      command: 'node server.js',
      url: `http://localhost:${API_PORT}/api/version`,
      reuseExistingServer: false,
      timeout: 120_000,
      stdout: 'ignore',
      stderr: 'pipe',
      env: {
        DB_PATH: scratchDbPath(),
        PORT: String(API_PORT),
        BIND_HOST: '127.0.0.1',
      },
    },
    {
      command: `npm run dev:ui -- --port ${UI_PORT} --strictPort`,
      url: baseURL,
      reuseExistingServer: false,
      timeout: 120_000,
      stdout: 'ignore',
      stderr: 'pipe',
      env: {
        API_PORT: String(API_PORT),
      },
    },
  ],
});
