import { formatError } from "./formatting.mjs";
import { runDalBatch, runHttpK6Batch } from "./default-runtime-runner.mjs";
import { runPlaywrightBatch } from "./playwright-runner.mjs";
import {
  cleanupWorker,
  ensureWorkerGraph,
  resetCurrentGraph,
} from "./runtime-contexts.mjs";

const HTTP_K6_TYPES = new Set(["integration", "e2e", "load"]);

export function createWorker(workerId, productDir) {
  return {
    workerId,
    productDir,
    currentGraphKey: null,
    graphContexts: new Map(),
    graphSwitches: 0,
    taskCount: 0,
  };
}

export async function runWorker(
  worker,
  queue,
  graphByKey,
  trackers,
  timingUpdates,
  lifecycle,
  claimNextBatch,
  recordTaskOutcome,
  recordGraphError
) {
  const startedAt = Date.now();
  console.log(`\n══ global worker ${worker.workerId} ══`);
  const errors = [];

  try {
    while (true) {
      if (lifecycle.isStopRequested()) break;
      const batch = claimNextBatch(queue, worker.currentGraphKey);
      if (!batch) break;

      try {
        const context = await ensureWorkerGraph(worker, batch, graphByKey, lifecycle);
        const outcomes = await runBatch(context, batch, lifecycle);
        for (const outcome of outcomes) {
          recordTaskOutcome(trackers, outcome.task, outcome);
          timingUpdates.push({
            key: outcome.task.timingKey,
            durationMs: outcome.durationMs,
          });
          worker.taskCount += 1;
        }
      } catch (error) {
        const message = formatError(error);
        errors.push(message);
        recordGraphError(trackers, graphByKey.get(batch.graphKey), message);
        await resetCurrentGraph(worker, lifecycle);
      }
    }
  } finally {
    await cleanupWorker(worker, lifecycle);
  }

  return {
    workerId: worker.workerId,
    failed: errors.length > 0,
    durationMs: Date.now() - startedAt,
    taskCount: worker.taskCount,
    graphSwitches: worker.graphSwitches,
    errors,
  };
}

async function runBatch(context, batch, lifecycle) {
  const targetConfig = context.configByName.get(batch.targetName);
  if (!targetConfig) {
    throw new Error(`Worker graph missing target config "${batch.targetName}"`);
  }

  if (batch.framework === "playwright") {
    return runPlaywrightBatch(targetConfig, batch, lifecycle);
  }
  if (batch.type === "dal") {
    return runDalBatch(targetConfig, batch, lifecycle);
  }
  if (batch.framework === "k6" && HTTP_K6_TYPES.has(batch.type)) {
    return runHttpK6Batch(targetConfig, batch, lifecycle);
  }

  throw new Error(
    `Unsupported task combination for ${batch.targetName}: type=${batch.type} framework=${batch.framework}`
  );
}
