import path from "path";
import {
  buildCompactRunSummaryLines,
  buildDebugRunSummaryLines,
  formatDuration,
} from "../../runner/formatting.mjs";
import { colorSectionLine, colorStatus, dim } from "./colors.mjs";

export function createRunReporter({ outputMode = "compact", stdout = process.stdout, stderr = process.stderr } = {}) {
  const mode = outputMode || "compact";
  return {
    outputMode: mode,
    writeLine(line = "") {
      stdout.write(`${line}\n`);
    },
    writeDebugLine(line = "") {
      stdout.write(`${line}\n`);
    },
    phaseStarted(label) {
      if (mode !== "debug") return;
      stdout.write(`\n── ${label} ──\n`);
    },
    toolchainResolved(config, resolvedToolchain) {
      if (mode !== "debug") return;
      stdout.write(
        `[testkit] ${config.runtimeLabel || config.name}:${config.name} toolchain ${resolvedToolchain.summary}\n`
      );
    },
    setupOperationFinished(operation) {
      if (!operation) return;
      if (mode === "json") return;
      if (operation.status === "cached") return;
      const duration = formatDuration(operation.durationMs || 0);
      if (operation.status === "failed") {
        const detail = shortenMessage(operation.error || operation.summary || operation.stage);
        stdout.write(
          `${colorStatus("FAIL")} ${"SETUP"} ${operation.serviceName} ${operation.stage} ${dim(duration)} ${detail}\n`
        );
        return;
      }
      if (
        mode === "compact" &&
        isHighLevelSetupOperation(operation) &&
        (operation.durationMs || 0) >= 5_000
      ) {
        const summary = shortenMessage(operation.summary || operation.stage);
        stdout.write(`${colorStatus("RUN")} ${"SETUP"} ${operation.serviceName} ${summary} ${dim(duration)}\n`);
      }
    },
    localServiceStarting(config, command) {
      if (mode !== "debug") return;
      stdout.write(`Starting ${config.runtimeLabel}:${config.name}: ${command}\n`);
    },
    serviceSkipped(config, reason) {
      stdout.write(`${colorStatus("SKIP")} ${config.name} ${reason}\n`);
    },
    plannedSkip(entry) {
      stdout.write(
        `${colorStatus("SKIP")} ${entry.serviceName} ${entry.type} ${normalizePath(entry.file)} ${dim("0s")} ${shortenMessage(entry.reason || "skipped")}\n`
      );
    },
    taskStarted(task, targetConfig) {
      if (mode !== "debug") return;
      stdout.write(`${colorStatus("RUN").padEnd(12)} ${targetConfig.name} ${task.type} ${task.file}\n`);
    },
    taskFinished(task, outcome) {
      if (mode === "json") return;
      const status = outcome.status === "skipped" ? "SKIP" : outcome.failed ? "FAIL" : "PASS";
      const duration = formatDuration(outcome.durationMs || 0);
      const primaryFailure = firstFailureDetail(outcome);
      const preferredFailure =
        primaryFailure && isThresholdWrapperMessage(outcome.error) ? primaryFailure : outcome.error || primaryFailure;
      const detail =
        status === "FAIL"
          ? ` ${shortenMessage(preferredFailure || "failed")}`
          : outcome.status === "not_run"
            ? ` ${shortenMessage(outcome.reason || "not run")}`
            : "";
      stdout.write(
        `${colorStatus(status)} ${task.serviceName} ${displayTaskType(task)} ${normalizePath(task.file)} ${dim(duration)}${detail}\n`
      );
    },
    telemetry(message) {
      if (mode === "json") return;
      stdout.write(`${message}\n`);
    },
    runSummary(results, durationMs, knownFailureIssueValidation = null) {
      const lines =
        mode === "debug"
          ? buildDebugRunSummaryLines(results, durationMs, knownFailureIssueValidation)
          : buildCompactRunSummaryLines(results, durationMs, knownFailureIssueValidation);
      for (const line of lines) stdout.write(`${colorSectionLine(line)}\n`);
    },
    error(message) {
      stderr.write(`${message}\n`);
    },
  };
}

function displayTaskType(task) {
  if (task.framework === "playwright") return "pw";
  if (task.type === "integration") return "int";
  return task.type;
}

function shortenMessage(message) {
  return String(message).replace(/\s+/g, " ").trim().slice(0, 180);
}

function firstFailureDetail(outcome) {
  const detail = outcome.failureDetails?.[0];
  return detail?.message || detail?.title || null;
}

function isThresholdWrapperMessage(message) {
  return /Default runtime thresholds failed:/.test(String(message || ""));
}

function normalizePath(filePath) {
  return String(filePath).split(path.sep).join("/");
}

function isHighLevelSetupOperation(operation) {
  return operation.kind === "database-template" || operation.kind === "runtime-prepare";
}
