import path from "path";
import { execa } from "execa";
import {
  parsePlaywrightJsonResults,
} from "../reporters/playwright.mjs";
import { resolveServiceCwd, } from "../config/index.mjs";
import { formatPlaywrightBatchFiles } from "./formatting.mjs";
import { printBufferedOutput } from "./processes.mjs";
import { ensurePlaywrightTestConfig } from "./playwright-config.mjs";
import { buildPlaywrightEnv } from "./template.mjs";
import { normalizePathSeparators } from "./state.mjs";

export async function runPlaywrightBatch(targetConfig, batch, lifecycle) {
  const local = targetConfig.testkit.local;
  if (!local?.baseUrl) {
    throw new Error(
      `Service "${targetConfig.name}" requires local.baseUrl for Playwright suites`
    );
  }

  console.log(
    `\n── ${targetConfig.workerLabel} playwright:${targetConfig.name} (${batch.tasks.length} file${batch.tasks.length === 1 ? "" : "s"})${formatPlaywrightBatchFiles(batch)} ──`
  );

  const cwd = resolveServiceCwd(targetConfig.productDir, local.cwd);
  const requestedFiles = batch.tasks.map((task) =>
    path.relative(cwd, path.join(targetConfig.productDir, task.file))
  );
  const playwrightConfigPath = ensurePlaywrightTestConfig(targetConfig, cwd, requestedFiles);
  const startedAt = Date.now();
  const result = await execa(
    "npx",
    ["playwright", "test", "--config", playwrightConfigPath, "--reporter=json"],
    {
      cwd,
      env: buildPlaywrightEnv(targetConfig, local.baseUrl, process.env),
      reject: false,
      cancelSignal: lifecycle.signal,
      forceKillAfterDelay: 5_000,
    }
  );

  if (result.stderr) {
    printBufferedOutput(result.stderr, `[${targetConfig.workerLabel}:${targetConfig.name}:playwright]`);
  }

  const parsed = parsePlaywrightJsonResults(result.stdout, cwd);
  const finishedAt = Date.now();
  const batchDurationMs = finishedAt - startedAt;
  const genericError =
    result.exitCode === 0
      ? parsed.errors[0] || null
      : parsed.errors[0] ||
        result.stderr.trim() ||
        `Playwright exited with code ${result.exitCode}`;

  return batch.tasks.map((task) => {
    const relativeFile = normalizePathSeparators(
      path.relative(cwd, path.join(targetConfig.productDir, task.file))
    );
    const fileResult = parsed.fileResults.get(relativeFile);
    if (fileResult) {
      return {
        task,
        failed: fileResult.status === "failed",
        status: fileResult.status,
        error: fileResult.error,
        durationMs:
          fileResult.durationMs > 0
            ? fileResult.durationMs
            : Math.round(batchDurationMs / Math.max(1, batch.tasks.length)),
        startedAt,
        finishedAt,
      };
    }

    return {
      task,
      failed: result.exitCode !== 0,
      error: result.exitCode !== 0 ? genericError : null,
      durationMs: Math.round(batchDurationMs / Math.max(1, batch.tasks.length)),
      startedAt,
      finishedAt,
    };
  });
}
