import { defineConfig, devices } from '@playwright/test'

import { CoverageReportOptions } from 'monocart-reporter'

// Directories that should not be covered by the coverage report
const dirsToNotCover = ['node_modules', 'backend']

const coverageReportOptions: CoverageReportOptions = {
  // logging: 'debug',
  name: 'Vite.js V8 Coverage Report',

  // Vite serves assets from /assets/ and source files from /src/
  entryFilter: (entry) => {
    // Filter for Vite client-side chunks (adjust as needed for your build output)
    return entry.url.includes('/assets/') || entry.url.includes('/src/')
  },

  sourceFilter: (sourcePath) => {
    if (dirsToNotCover.some((dir) => sourcePath.includes(dir))) {
      return false
    }
    // Vite source files are typically under /src
    return sourcePath.includes('src')
  },

  sourcePath: (fileSource) => {
    return fileSource
  },

  reports: ['v8', 'html', 'lcov'],
}

import z from 'zod'

// We use zod to read and validate the configuration from environment variables.
const TEST_CONFIG_SCHEMA = z
  .object({
    apiURL: z.string(),
    baseURL: z.string(),
    enableVideo: z.boolean().optional().default(false),
    isCI: z.boolean().optional().default(false),
    workers: z.number().optional(),
    maxDiffPixels: z.number().optional().default(100),
    enableBackendShutdown: z.boolean().optional().default(false),
    // stateful: z.boolean().optional().default(false),
  })
  .transform((config) => ({
    ...config,
    apiPort: new URL(config.apiURL).port || 3001,
  }))

export const TEST_CONFIG = TEST_CONFIG_SCHEMA.parse({
  apiURL: nextenv(process.env.API_URL),
  baseURL: nextenv(process.env.BASE_URL),
  enableVideo: nextenv(process.env.ENABLE_VIDEO),
  isCI: nextenv(process.env.CI),
  workers: nextenv(process.env.PLAYWRIGHT_WORKERS),
  maxDiffPixels: nextenv(process.env.MAX_DIFF_PIXELS),
  enableBackendShutdown: nextenv(process.env.ENABLE_BACKEND_SHUTDOWN),
  // stateful: nextenv(process.env.STATEFUL),
})

function nextenv(value?: string | null): string | boolean | number | null | undefined {
  if (value == null) {
    return value
  }

  try {
    return JSON.parse(value) as string | boolean | number | null | undefined
  } catch {
    // If we can't parse the value as JSON, just return the original value as string.
    return value
  }
}

// Zod validation is done in the `TEST_CONFIG` object.
// We can access the values from the `TEST_CONFIG` object.

const isVideoEnabled = TEST_CONFIG.enableVideo ? 'on' : 'off'

export default defineConfig({
  globalSetup: require.resolve('./fixtures/global-setup'),

  // If running in "stateful" mode, run tests that are not marked as stateless.
  // Otherwise, run tests that are not marked as stateful.
  // testMatch: TEST_CONFIG.stateful ? '**/!(*.stateless).+(test|spec).ts' : '**/!(*.stateful).+(test|spec).ts',

  // We enable test retries. When `retries` option is used, failing tests will be retried until they pass or up to the specified number of times.
  // Here we retry twice.
  retries: 2,

  use: {
    // Traces are run on CI on the first retry of a failed test. This is done by setting the `trace` option to 'on-first-retry'.
    // This will produce a trace directory in test result artifacts.
    // This will also produce a `trace.zip` file for each test that was retried, they are saved in `test-results` directory.
    trace: 'on-first-retry',
    baseURL: TEST_CONFIG.baseURL,
    testIdAttribute: 'data-test-id',
    viewport: { width: 1920, height: 1080 },
    video: {
      mode: isVideoEnabled,
      size: { width: 1920, height: 1080 },
    },
  },

  expect: {
    toHaveScreenshot: {
      // Default maxDiffPixels is set to 100 for regular test runs to allow for minor rendering differences
      // across different environments, browsers, or system configurations. However, when updating snapshots
      // via the e2e:update-snapshots script, we use a stricter threshold of 50 pixels to ensure new
      // snapshots are more precise and catch smaller visual regressions in future test runs.
      maxDiffPixels: TEST_CONFIG.maxDiffPixels,
      threshold: 0.15,
    },
  },

  // Dynamically set the number of workers based on the test configuration.
  // In "stateful" mode, limit the workers to 1 to avoid concurrency issues.
  // Otherwise, use the value from TEST_CONFIG.workers, or default to half the available CPU cores if not specified.
  // Note: Playwright calculates the default number of workers as (# CPU cores) / 2.
  workers: TEST_CONFIG.workers,

  //  We can generate a report in different formats, use the following:
  // 'github' for GitHub Actions CI to generate annotations,
  // 'html' to produce a report in HTML format,
  // 'list' to print a line for each test being run and a summary is saved at the end of the run.
  //  Here we use 'github', 'html' and monocart-reporter for CI,
  //  'list' and the monocart-reporter (test coverage generator) for local run.
  reporter: TEST_CONFIG.isCI
    ? [
        ['github'],
        ['html', { open: 'never' }],
        [
          'monocart-reporter',
          {
            coverage: coverageReportOptions,
          },
        ],
      ]
    : [
        ['list'],
        [
          'monocart-reporter',
          {
            coverage: coverageReportOptions,
          },
        ],
      ],

  projects: [
    // use chromium to allow coverage reports
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        viewport: { width: 1920, height: 1080 },
      },
    },
  ],
  globalTeardown: require.resolve('./fixtures/global-teardown'),
})
