import { defineConfig, devices, type ReporterDescription } from '@playwright/test';
import { join } from 'node:path';
import { isExternalBaseUrl, loadPlaywrightEnv } from './tests/e2e/helpers/env';
import { playwrightWorkerCount } from './tests/e2e/factories/actor-sets';

const shellBaseUrl = process.env.BASE_URL;
const configDir = new URL('.', import.meta.url).pathname;
const chromiumLaunchOptions = {
  args: [
    '--disable-dev-shm-usage',
    '--disable-gpu',
    '--disable-extensions',
    '--disable-background-timer-throttling',
    '--disable-renderer-backgrounding',
    '--disable-backgrounding-occluded-windows',
  ],
};
const factoryMode = process.env.E2E_FACTORY_MODE === '1';
// Factory mode: run-factory-e2e.mjs owns the full env contract (factory DB URL,
// run-scoped secrets). Loading .dev.vars here would override it with developer
// values and silently repoint the worker at the live database.
if (!factoryMode) {
  loadPlaywrightEnv(shellBaseUrl, [join(configDir, '.env'), join(configDir, '.dev.vars')]);
}

const PORT = Number(process.env.PORT ?? 4321);
const BASE_URL = shellBaseUrl ?? process.env.BASE_URL ?? `http://localhost:${PORT}`;
process.env.BASE_URL = BASE_URL;

// When BASE_URL points to a deployed environment (e.g. dev.multi.deal), skip the
// local webServer entirely — the app is already running externally.
const isExternalUrl = !factoryMode && isExternalBaseUrl(BASE_URL);

const reporters: ReporterDescription[] = process.env.PLAYWRIGHT_BLOB_OUTPUT_DIR
  ? [
      [
        'blob',
        {
          outputDir: process.env.PLAYWRIGHT_BLOB_OUTPUT_DIR,
          fileName: process.env.PLAYWRIGHT_BLOB_FILE_NAME ?? 'report.zip',
        },
      ],
      // blob writes only to disk, so without this a webServer that dies during
      // startup reports "Exit code: 1" with nothing about why.
      ['list'],
    ]
  : process.env.CI
    ? [['github'], ['html']]
    : [['list']];
// Playwright resolves the json reporter's destination from these vars itself.
// Added alongside (never replacing) the human reporter so the failure list
// survives on disk even when stdout capture is truncated.
if (process.env.PLAYWRIGHT_JSON_OUTPUT_FILE || process.env.PLAYWRIGHT_JSON_OUTPUT_NAME)
  reporters.push(['json']);
if (process.env.E2E_RUN_RECEIPT_PATH && !process.argv.includes('--list'))
  reporters.push([
    './scripts/e2e-run-receipt-reporter.mjs',
    { outputFile: process.env.E2E_RUN_RECEIPT_PATH },
  ]);

export default defineConfig({
  testDir: './tests',
  globalSetup: factoryMode
    ? './tests/e2e/factories/global-setup.ts'
    : './tests/e2e/purchase-flows/fixtures/purchase-seed.ts',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: factoryMode ? 0 : process.env.CI ? 2 : 1,
  workers: playwrightWorkerCount(factoryMode),
  // Factory journeys hit real checkout/RMA/support flows; 30s default times out in the
  // certified full-suite batch even though per-spec runs pass with the same code.
  ...(factoryMode && {
    timeout: 120_000,
    expect: { timeout: 15_000 },
  }),
  reporter: reporters,
  use: {
    baseURL: BASE_URL,
    trace: 'on-first-retry',
    video: 'off',
    screenshot: 'only-on-failure',
    locale: 'he-IL',
    timezoneId: 'Asia/Jerusalem',
  },
  projects: [
    // NOTE: mobile-chrome uses Chromium engine so browser.browserType().name()
    // returns 'chromium' for both chromium + mobile-chrome projects.
    // Use testInfo.project.name (not browserType) to guard chromium-only sections.
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'], launchOptions: chromiumLaunchOptions },
    },
    { name: 'mobile-chrome', use: { ...devices['Pixel 7'], launchOptions: chromiumLaunchOptions } },
    { name: 'mobile-safari', use: { ...devices['iPhone 14'] } },
  ],
  // No webServer when targeting a deployed external URL
  ...(!isExternalUrl && {
    webServer: factoryMode
      ? {
          command: 'node scripts/factory-preview-server.mjs',
          // /api/health is `db: 'none'` and SSR — a prerendered asset such as
          // /maintenance answers even when the worker never instantiates.
          url: `${BASE_URL}/api/health`,
          reuseExistingServer: false,
          timeout: 120_000,
          stdout: 'pipe',
          stderr: 'pipe',
        }
      : process.env.CI
        ? {
            command: 'pnpm preview',
            url: BASE_URL,
            reuseExistingServer: false,
            timeout: 120_000,
          }
        : {
            command: 'ASTRO_DEV_BACKGROUND=1 pnpm dev',
            url: BASE_URL,
            reuseExistingServer: true,
            timeout: 120_000,
          },
  }),
});
