import { formatDuration } from "../../runner/formatting.mjs";
import { formatSelectionTypeLabel } from "../../discovery/index.mjs";
import {
  bold,
  colorDiagnosticSeverity,
  colorHeading,
  colorService,
  colorStatus,
  colorTypeBadge,
  muted,
} from "./colors.mjs";

const TYPE_ORDER = ["int", "e2e", "scenario", "dal", "load", "pw"];

export function buildDiscoveryReportLines(result, options = {}) {
  const mode = options.outputMode || "compact";
  return mode === "verbose" ? buildVerboseLines(result) : buildCompactLines(result);
}

function buildCompactLines(result) {
  const lines = [];
  lines.push(
    `${colorHeading("Summary")} ${result.summary.files} files · ${result.summary.activeFiles} active · ${result.summary.skippedFiles} skipped · ${result.summary.suites} suites · ${result.summary.services} services`
  );

  if (result.history?.available) {
    lines.push(muted(`history ${result.history.path || ".testkit/history/tests.json"}`));
  }

  appendDiagnostics(lines, result.diagnostics);

  const suitesByService = groupSuitesByServiceAndType(result.suites);
  const filesBySuite = groupFilesBySuite(result.files);

  for (const service of result.services) {
    lines.push("");
    lines.push(
      `${colorService(service.name)} ${muted(`(${service.fileCount} files${service.dependsOn.length > 0 ? ` · depends on ${service.dependsOn.join(", ")}` : ""})`)}`
    );
    const typeGroups = suitesByService.get(service.name) || new Map();
    for (const type of orderedTypes([...typeGroups.keys()])) {
      const suites = typeGroups.get(type) || [];
      lines.push(`  ${colorTypeBadge(type.toUpperCase())} ${formatSelectionTypeLabel(type)}`);
      for (const suite of suites) {
        lines.push(`    ${bold(suite.groupLabel)} ${muted(`(${suite.fileCount} files)`)}`);
        for (const file of filesBySuite.get(suite.id) || []) {
          const status = file.skipped ? `${colorStatus("SKIP")} ${file.skipReason}` : muted(buildHistoryHint(file));
          lines.push(`      ${file.displayName}${status ? `  ${status}` : ""}`);
        }
      }
    }
  }

  return lines;
}

function buildVerboseLines(result) {
  const lines = [];
  lines.push(`${colorHeading("Summary")} ${JSON.stringify(result.summary)}`);
  if (result.setupFile) {
    lines.push(`setup ${result.setupFile}`);
  }
  if (result.history?.available) {
    lines.push(`history ${result.history.path}`);
  }

  appendDiagnostics(lines, result.diagnostics);

  for (const service of result.services) {
    lines.push("");
    lines.push(colorService(service.name));
    lines.push(`  cwd ${service.localCwd}`);
    if (service.dependsOn.length > 0) {
      lines.push(`  dependsOn ${service.dependsOn.join(", ")}`);
    }
    lines.push(`  files ${service.fileCount} · active ${service.activeFileCount} · skipped ${service.skippedFileCount}`);

    const suites = result.suites.filter((suite) => suite.service === service.name).sort(compareSuites);
    for (const suite of suites) {
      lines.push(
        `  suite ${suite.selectionType}:${suite.name} ${muted(`[${suite.framework}]`)} ${muted(`${suite.fileCount} files`)}`
      );
      if (suite.locks.length > 0) {
        lines.push(`    locks ${suite.locks.join(", ")}`);
      }
      for (const file of result.files.filter((entry) => entry.service === service.name && entry.suiteName === suite.name && entry.selectionType === suite.selectionType)) {
        lines.push(`    ${file.displayName}`);
        lines.push(`      path ${file.path}`);
        lines.push(`      id ${file.id}`);
        lines.push(`      status ${file.skipped ? "skipped" : "active"}`);
        if (file.skipReason) lines.push(`      skipReason ${file.skipReason}`);
        if (file.locks.length > 0) lines.push(`      locks ${file.locks.join(", ")}`);
        if (file.history) {
          lines.push(
            `      history runs=${file.history.runCount} pass=${file.history.passCount} fail=${file.history.failCount} skip=${file.history.skipCount} avg=${file.history.avgDurationMs > 0 ? formatDuration(file.history.avgDurationMs) : "0s"} last=${file.history.lastStatus || "unknown"} firstSeen=${file.history.firstSeenAt || "unknown"}`
          );
        }
      }
    }
  }

  return lines;
}

function appendDiagnostics(lines, diagnostics = []) {
  if (!diagnostics.length) return;
  lines.push("");
  lines.push(colorHeading("Diagnostics"));
  for (const entry of diagnostics) {
    const location = entry.path ? ` ${entry.path}` : "";
    lines.push(`  ${colorDiagnosticSeverity(entry.severity)} ${entry.code}${location}`);
    lines.push(`    ${entry.message}`);
  }
}

function groupSuitesByServiceAndType(suites) {
  const grouped = new Map();
  for (const suite of suites) {
    let byType = grouped.get(suite.service);
    if (!byType) {
      byType = new Map();
      grouped.set(suite.service, byType);
    }
    const list = byType.get(suite.selectionType) || [];
    list.push(suite);
    byType.set(suite.selectionType, list.sort(compareSuites));
  }
  return grouped;
}

function groupFilesBySuite(files) {
  const bySuite = new Map();
  for (const file of files) {
    const suiteId = [file.service, file.selectionType, file.framework, file.suiteName].join("|");
    const list = bySuite.get(suiteId) || [];
    list.push(file);
    bySuite.set(
      suiteId,
      list.sort((left, right) => left.displayName.localeCompare(right.displayName) || left.path.localeCompare(right.path))
    );
  }
  return bySuite;
}

function orderedTypes(types) {
  return [...types].sort((left, right) => TYPE_ORDER.indexOf(left) - TYPE_ORDER.indexOf(right));
}

function compareSuites(left, right) {
  return left.groupLabel.localeCompare(right.groupLabel) || left.name.localeCompare(right.name);
}

function buildHistoryHint(file) {
  if (!file.history) return "";
  const totalCompleted = file.history.passCount + file.history.failCount;
  const passRate = totalCompleted > 0 ? `${Math.round((file.history.passCount / totalCompleted) * 100)}% pass` : "no result history";
  const avg = file.history.avgDurationMs > 0 ? formatDuration(file.history.avgDurationMs) : null;
  return [
    `${file.history.runCount} ${file.history.runCount === 1 ? "run" : "runs"}`,
    passRate,
    avg ? `avg ${avg}` : null,
    file.history.firstSeenAt ? `seen ${file.history.firstSeenAt.slice(0, 10)}` : null,
  ]
    .filter(Boolean)
    .join(" · ");
}
