import { defineConfig, devices } from '@playwright/test'
import {
  STORAGE_STATE,
  STORAGE_STATE_NO_PIN,
  STORAGE_STATE_DELETE,
  STORAGE_STATE_CC,
  STORAGE_STATE_TUTORIAL,
} from './e2e/e2e-constants'

/**
 * E2E MongoDB configuration is hardcoded below.  Developers can override
 * values via environment variables; see .env.test for an example.
 */

/**
 * See https://playwright.dev/docs/test-configuration.
 */
const frontendBaseUrl = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173'

export default defineConfig({
  testDir: './e2e',
  /* Run tests in files in parallel */
  fullyParallel: true,
  /* Fail the build on CI if you accidentally left test.only in the source code. */
  forbidOnly: !!process.env.CI,
  /* Retry on CI only */
  retries: process.env.CI ? 2 : 0,
  /* Opt out of parallel tests on CI. */
  workers: process.env.CI ? 1 : undefined,
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
  reporter: 'html',
  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
  use: {
    /* Base URL to use in actions like `await page.goto('')`. */
    baseURL: frontendBaseUrl,
    ignoreHTTPSErrors: true,

    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
    trace: 'on-first-retry',
  },

  /* Configure projects for major browsers */
  projects: [
    { name: 'setup', testMatch: /auth\.setup\.ts/ },
    { name: 'setup-no-pin', testMatch: /auth-no-pin\.setup\.ts/ },
    // Depends on 'setup' because e2e-seed (run in setup) truncates all users first.
    { name: 'setup-delete', testMatch: /auth-delete\.setup\.ts/, dependencies: ['setup'] },
    { name: 'setup-cc', testMatch: /auth-cc\.setup\.ts/, dependencies: ['setup'] },
    {
      name: 'setup-tutorial',
      testMatch: /auth-tutorial\.setup\.ts/,
      // Depends on setup because e2e-seed truncates all users first.
      dependencies: ['setup'],
    },

    {
      // Bucket A: child-options tests — run before create-child so that
      // deleteAllChildren() in happy-path.spec.ts cannot delete children
      // that these tests are actively using.
      name: 'chromium-child-options',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/child-options\/.+\.spec\.ts/],
    },

    {
      // Bucket B: create-child tests — uses its own isolated user (e2e-cc@test.com)
      // so deleteAllChildren() only affects that user's children and never interferes
      // with concurrent buckets using the main E2E user.
      name: 'chromium-create-child',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_CC },
      dependencies: ['setup-cc'],
      testMatch: [/mode_parent\/create-child\/.+\.spec\.ts/],
    },

    {
      // Bucket: tests that mutate shared system-default items (chores/kindness/penalties).
      // fullyParallel:false prevents files from being split across workers;
      // the merged kindness-default and penalty-default files use mode:'serial'
      // internally to guarantee the convert and delete tests never run in parallel.
      // API-based beforeEach cleanup in each spec makes these tests resilient to
      // concurrent SSE activity from other buckets.
      name: 'chromium-default-tasks',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/tasks\/.*default\.spec\.ts/],
      fullyParallel: false,
    },

    {
      // Bucket: task and reward assignment tests for individual children.
      // Serial mode within each file ensures assign → verify → unassign → cancel flow order.
      name: 'chromium-task-assignment',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/task-assignment\/.+\.spec\.ts/],
    },

    {
      // Bucket: task activation and reward redemption tests — each spec creates its own
      // isolated child so the 4 files can safely run in parallel within this bucket.
      name: 'chromium-task-activation',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/task-activation\/.+\.spec\.ts/],
    },

    {
      // Bucket: task modification tests — each spec creates its own isolated child
      // so the 6 files can safely run in parallel within this bucket.
      name: 'chromium-task-modification',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/task-modification\/.+\.spec\.ts/],
    },

    {
      // Bucket: chore scheduler tests — each spec creates isolated child+chores.
      name: 'chromium-chore-scheduler',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/chore-scheduler\/.+\.spec\.ts/],
    },

    {
      // Bucket: parent notifications tests — push subscription, chore/reward
      // notification approval/denial, deep-link navigation, digest tokens, and
      // user profile notification settings. Each spec creates its own isolated child.
      name: 'chromium-parent-notifications',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/notifications\/.+\.spec\.ts/],
    },

    {
      // Bucket: routine tests — child-mode overlay flow (confirm + cancel) and
      // parent notification appearance. Each spec creates its own isolated child.
      name: 'chromium-routines',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/routines\/.+\.spec\.ts/],
    },

    {
      // Bucket: parent profile button tests (permanent parent mode).
      name: 'chromium-profile-button',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/profile-button\/.+\.spec\.ts/],
    },

    {
      // Bucket: user profile editing tests (name, image, save/cancel, change password).
      name: 'chromium-user-profile',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/user-profile\/profile-editing\.spec\.ts/],
    },

    {
      // Bucket: change PIN flow tests — restores the original PIN in afterAll.
      name: 'chromium-user-profile-pin',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testMatch: [/mode_parent\/user-profile\/change-pin\.spec\.ts/],
    },

    {
      // Bucket: delete account tests — uses its own isolated user (e2e-delete@test.com)
      // so the shared E2E session is never affected and no cross-project dependencies needed.
      name: 'chromium-user-profile-delete',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_DELETE },
      dependencies: ['setup-delete'],
      testMatch: [/mode_parent\/user-profile\/delete-account\.spec\.ts/],
    },

    {
      // Bucket: tutorial system tests — uses an isolated user so tutorial
      // enabled/progress state never interferes with other buckets.
      name: 'chromium-tutorial',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_TUTORIAL },
      dependencies: ['setup-tutorial'],
      testMatch: [/mode_parent\/tutorial\/.+\.spec\.ts/],
      testIgnore: [/mode_parent\/tutorial\/dialog-help-button\.spec\.ts/],
    },

    {
      // Bucket: dialog help-button/title tests — depends on the tutorial bucket
      // so it reuses the isolated tutorial user without running concurrently.
      name: 'chromium-dialog',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_TUTORIAL },
      dependencies: ['chromium-tutorial'],
      testMatch: [/mode_parent\/tutorial\/dialog-help-button\.spec\.ts/],
    },

    {
      name: 'chromium-tasks-rewards',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE },
      dependencies: ['setup'],
      testIgnore: [
        /\/mode_child\//,
        /mode_parent\/(create-child|child-options)\//,
        /mode_parent\/tasks\/.*default\.spec\.ts/,
        /mode_parent\/task-assignment\//,
        /mode_parent\/task-activation\//,
        /mode_parent\/task-modification\//,
        /mode_parent\/profile-button\//,
        /mode_parent\/user-profile\//,
        /mode_parent\/chore-scheduler\//,
        /mode_parent\/notifications\//,
        /mode_parent\/routines\//,
        /mode_parent\/tutorial\//,
      ],
    },

    {
      name: 'chromium-no-pin',
      use: { ...devices['Desktop Chrome'], storageState: STORAGE_STATE_NO_PIN },
      dependencies: ['setup-no-pin'],
      // never run the large task suite or the SSE cross‑tab tests when the parent
      // pin is removed – they are slow and rely on long‑lived connections.
      testIgnore: [/\/mode_parent\//],
    },

    // {
    //   name: 'firefox',
    //   use: { ...devices['Desktop Firefox'] },
    // },

    // {
    //   name: 'webkit',
    //   use: { ...devices['Desktop Safari'] },
    // },

    /* Test against mobile viewports. */
    // {
    //   name: 'Mobile Chrome',
    //   use: { ...devices['Pixel 5'] },
    // },
    // {
    //   name: 'Mobile Safari',
    //   use: { ...devices['iPhone 12'] },
    // },

    /* Test against branded browsers. */
    // {
    //   name: 'Microsoft Edge',
    //   use: { ...devices['Desktop Edge'], channel: 'msedge' },
    // },
    // {
    //   name: 'Google Chrome',
    //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },
    // },
  ],
  /* Run your local dev server before starting tests */
  webServer: [
    {
      command: 'npm run dev',
      url: frontendBaseUrl,
      reuseExistingServer: !process.env.CI,
      stdout: 'pipe',
      stderr: 'pipe',
      ignoreHTTPSErrors: true,
    },
    {
      command:
        process.platform === 'win32'
          ? 'echo Platform: %PROCESS_PLATFORM% && .venv\\Scripts\\python.exe -m flask run --host=0.0.0.0 --port=5000 --no-debugger --no-reload'
          : 'echo Platform: $PROCESS_PLATFORM && .venv/bin/python -m flask run --host=0.0.0.0 --port=5000 --no-debugger --no-reload',
      url: 'http://localhost:5000/version',
      reuseExistingServer: !process.env.CI,
      stdout: 'pipe',
      stderr: 'pipe',
      cwd: '../backend',
      env: {
        FLASK_APP: 'main.py',
        FLASK_DEBUG: '1',
        DB_ENV: 'e2e',
        DATA_ENV: 'e2e',
        SECRET_KEY: 'dev-secret-key-change-in-production',
        ACCESS_TOKEN_EXPIRY_MINUTES: process.env.E2E_ACCESS_TOKEN_EXPIRY_MINUTES || '180',
        REFRESH_TOKEN_EXPIRY_DAYS: '90',
        DIGEST_TOKEN_SECRET: 'dev-digest-token',
        VAPID_PUBLIC_KEY:
          'BNKkHdq45uLigohSG7c1TwlAo7ETncoRVLQK02LxHgu2P1DgSJD9njRMfbbzUsaTQGllvLBz7An1WiWsNYQhvKE',
        VAPID_PRIVATE_KEY: 'jNiZJT0UO4H861KmnCt874Fg6p5jDAyYKS4V2MZf8bQ',
        PROCESS_PLATFORM: process.platform,
        USE_MONGODB: process.env.USE_MONGODB || 'true',
        MONGO_URI: process.env.MONGO_URI || 'mongomock',
      },
    },
  ],
  /* Run your local dev server before starting the tests */
  // webServer: {
  //   command: 'npm run start',
  //   url: 'http://localhost:3000',
  //   reuseExistingServer: !process.env.CI,
  // },
})
