import { buildKnownFailureIssueValidationSummaryLines } from "../known-failures/github.mjs";

export function formatDuration(durationMs) {
  const totalSeconds = Math.max(0, Math.round(durationMs / 1000));
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;
  if (minutes === 0) return `${seconds}s`;
  return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
}

export function formatServiceSummary(result) {
  const skippedSuites = result.skippedSuiteCount || 0;
  const passedSuites = result.completedSuiteCount - result.failedSuiteCount - skippedSuites;
  const notRunSuites = result.suiteCount - result.completedSuiteCount;
  let detail = `${passedSuites}/${result.suiteCount} suites passed`;
  if ((result.totalFileCount || 0) > 0) {
    detail += `, ${result.passedFileCount}/${result.totalFileCount} files passed`;
  }
  if (skippedSuites > 0) {
    detail += `, ${skippedSuites} ${pluralize(skippedSuites, "suite", "suites")} skipped`;
  } else if ((result.skippedFileCount || 0) > 0) {
    detail += `, ${result.skippedFileCount} ${pluralize(result.skippedFileCount, "file", "files")} skipped`;
  }
  if (notRunSuites > 0) {
    detail += `, ${notRunSuites} ${pluralize(notRunSuites, "suite", "suites")} not run`;
  } else if ((result.notRunFileCount || 0) > 0) {
    detail += `, ${result.notRunFileCount} ${pluralize(result.notRunFileCount, "file", "files")} not run`;
  }
  return detail;
}

export function formatError(error) {
  if (error instanceof Error) return sanitizeErrorMessage(error.message);
  return sanitizeErrorMessage(String(error));
}

export function longestServiceName(results) {
  return results.reduce((max, result) => Math.max(max, result.name.length), 4);
}

export function formatFrameworkLabel(framework) {
  if (!framework || framework === "k6") return "";
  return framework;
}

export function formatSuiteFramework(framework) {
  const label = formatFrameworkLabel(framework);
  return label ? ` [${label}]` : "";
}

export function buildRunSummaryLines(results, durationMs, knownFailureIssueValidation = null) {
  const totalServices = results.length;
  const executedServices = results.filter((result) => !result.skipped);
  const skippedServices = results.filter((result) => result.skipped);
  const failedServices = executedServices.filter((result) => result.failed);
  const passedServices = executedServices.filter((result) => !result.failed);
  const totalSuites = executedServices.reduce((sum, result) => sum + result.suiteCount, 0);
  const completedSuites = executedServices.reduce(
    (sum, result) => sum + result.completedSuiteCount,
    0
  );
  const skippedSuites = executedServices.reduce(
    (sum, result) => sum + (result.skippedSuiteCount || 0),
    0
  );
  const failedSuites = executedServices.reduce((sum, result) => sum + result.failedSuiteCount, 0);
  const passedSuites = completedSuites - failedSuites - skippedSuites;
  const totalFiles = executedServices.reduce((sum, result) => sum + (result.totalFileCount || 0), 0);
  const passedFiles = executedServices.reduce((sum, result) => sum + (result.passedFileCount || 0), 0);
  const skippedFiles = executedServices.reduce(
    (sum, result) => sum + (result.skippedFileCount || 0),
    0
  );
  const lines = [
    "",
    "══ Summary ══",
    [
      `services ${passedServices.length}/${executedServices.length} passed`,
      `suites ${passedSuites}/${totalSuites} passed`,
      totalFiles > 0 ? `files ${passedFiles}/${totalFiles} passed` : null,
      skippedSuites > 0 ? `suites ${skippedSuites} skipped` : null,
      skippedFiles > 0 ? `files ${skippedFiles} skipped` : null,
      skippedServices.length > 0 ? `${skippedServices.length} skipped` : null,
      `duration ${formatDuration(durationMs)}`,
    ]
      .filter(Boolean)
      .join("  ·  "),
  ];

  for (const result of results) {
    const status = isServiceEffectivelySkipped(result)
      ? "SKIP"
      : result.failed
        ? "FAIL"
        : "PASS";
    const detail = result.skipped
      ? "no matching suites"
      : formatServiceSummary(result);
    lines.push(
      `${status.padEnd(4)} ${result.name.padEnd(longestServiceName(results))}  ${detail}  ·  ${formatDuration(result.durationMs)}`
    );

    if (!result.failed) continue;

    for (const suite of result.suites.filter((entry) => entry.failed)) {
      const fileDetail =
        suite.failedFiles.length > 0 ? `  (${suite.failedFiles.join(", ")})` : "";
      lines.push(
        `  - ${suite.type}:${suite.name}${formatSuiteFramework(suite.framework)}${fileDetail} · ${formatDuration(suite.durationMs)}`
      );
      if (suite.error) {
        lines.push(`    ${suite.error}`);
      }
    }
    for (const error of result.errors) {
      lines.push(`  - worker error: ${error}`);
    }
  }

  const knownFailureIssueLines = buildKnownFailureIssueValidationSummaryLines(
    knownFailureIssueValidation
  );
  if (knownFailureIssueLines.length > 0) {
    lines.push(...knownFailureIssueLines);
  }

  if (failedServices.length > 0) {
    lines.push("", `Result: FAILED (${failedServices.length}/${totalServices} services failed)`);
    return lines;
  }

  lines.push("", "Result: PASSED");
  return lines;
}

function sanitizeErrorMessage(message) {
  return message
    .replace(/Command failed with exit code (\d+): .*?[\\/]vendor[\\/]k6 run\b/g, "Default runtime failed with exit code $1:")
    .replace(/Command failed with exit code (\d+): k6 run\b/g, "Default runtime failed with exit code $1:")
    .replace(/[\\/]vendor[\\/]k6\b/g, "default-runtime");
}

function pluralize(value, singular, plural) {
  return value === 1 ? singular : plural;
}

function isServiceEffectivelySkipped(result) {
  if (result.skipped) return true;
  return (
    !result.failed &&
    (result.skippedSuiteCount || 0) > 0 &&
    (result.skippedSuiteCount || 0) === result.suiteCount &&
    (result.notRunFileCount || 0) === 0
  );
}
