import fs from "fs";
import path from "path";
import { formatDuration } from "../runner/formatting.mjs";
import { readLogTail } from "../runner/logs.mjs";

export function loadLatestRunArtifact(productDir) {
  const artifactPath = path.join(productDir, ".testkit", "results", "latest.json");
  if (!fs.existsSync(artifactPath)) {
    throw new Error(`No run artifact found at ${path.relative(productDir, artifactPath)}`);
  }
  return JSON.parse(fs.readFileSync(artifactPath, "utf8"));
}

export function resolveFileSubject(runArtifact, selector = null, serviceFilter = null) {
  const files = collectFiles(runArtifact, serviceFilter);
  if (files.length === 0) {
    throw new Error("No file results were found in the latest run artifact.");
  }

  if (!selector) {
    return files.find((entry) => entry.file.status === "failed") || files[0];
  }

  const normalizedSelector = normalizePath(selector);
  const exact = files.filter((entry) => entry.file.path === normalizedSelector);
  if (exact.length === 1) return exact[0];
  if (exact.length > 1) {
    throw new Error(`Multiple files matched "${selector}". Re-run with --service to disambiguate.`);
  }

  const suffixMatches = files.filter((entry) => entry.file.path.endsWith(normalizedSelector));
  if (suffixMatches.length === 1) return suffixMatches[0];
  if (suffixMatches.length > 1) {
    throw new Error(`Multiple files matched "${selector}". Re-run with --service to disambiguate.`);
  }

  throw new Error(`No file matched "${selector}".`);
}

export function collectArtifactEntries(productDir, runArtifact, selector = null, serviceFilter = null) {
  const files = selector
    ? [resolveFileSubject(runArtifact, selector, serviceFilter)]
    : collectFiles(runArtifact, serviceFilter);
  const entries = [];

  for (const entry of files) {
    for (const artifactRef of entry.file.artifacts || []) {
      const absolutePath = path.join(productDir, artifactRef.path);
      const payload = fs.existsSync(absolutePath)
        ? JSON.parse(fs.readFileSync(absolutePath, "utf8"))
        : null;
      entries.push({
        ...entry,
        artifactRef,
        absolutePath,
        payload,
      });
    }
  }

  return entries;
}

export function formatFileDetail(productDir, runArtifact, subject, options = {}) {
  const lines = [];
  lines.push(`File: ${subject.file.path}`);
  lines.push(`Service: ${subject.service.name}`);
  lines.push(`Suite: ${subject.suite.type}:${subject.suite.name}`);
  lines.push(`Status: ${subject.file.status}`);
  lines.push(`Duration: ${formatDuration(subject.file.durationMs || 0)}`);
  if (subject.file.error) lines.push(`Error: ${subject.file.error}`);

  if ((subject.file.failureDetails || []).length > 0) {
    lines.push("");
    lines.push("Failure Details:");
    for (const detail of subject.file.failureDetails.slice(0, options.failureLimit || 5)) {
      lines.push(`  ${detail.title}`);
      if (detail.message) lines.push(`    ${detail.message}`);
    }
  }

  const artifacts = collectArtifactEntries(productDir, runArtifact, subject.file.path, subject.service.name);
  if (artifacts.length > 0) {
    lines.push("");
    lines.push("Artifacts:");
    for (const entry of artifacts) {
      lines.push(`  ${entry.artifactRef.name}${entry.artifactRef.kind ? ` [${entry.artifactRef.kind}]` : ""}`);
      if (entry.artifactRef.summary) lines.push(`    ${entry.artifactRef.summary}`);
      for (const previewLine of formatArtifactPreview(entry.payload, options.previewLength || 6)) {
        lines.push(`    ${previewLine}`);
      }
      lines.push(`    ${entry.artifactRef.path}`);
    }
  }

  const logRefs = getServiceLogRefs(runArtifact, subject.service.name);
  if (logRefs.length > 0) {
    lines.push("");
    lines.push("Backend Logs:");
    for (const logRef of logRefs) {
      lines.push(`  ${logRef.runtimeLabel}`);
      lines.push(`    ${logRef.path}`);
      const tail = readLogTail(path.join(productDir, logRef.path), options.logTail || 12);
      for (const line of tail.slice(-Math.max(0, options.logTail || 12))) {
        lines.push(`    ${line}`);
      }
    }
  }

  return lines;
}

export function getServiceLogRefs(runArtifact, serviceName) {
  return (runArtifact.logs?.services || []).filter((entry) => entry.serviceName === serviceName);
}

export function formatArtifactPreview(payload, maxLines = 6) {
  if (!payload) return ["artifact payload missing"];
  if (payload.kind === "agentic-query") {
    return formatAgenticArtifact(payload, maxLines);
  }
  if (payload.contentType === "text/plain" && typeof payload.data?.text === "string") {
    return payload.data.text
      .split(/\r?\n/)
      .filter((line) => line.trim().length > 0)
      .slice(0, maxLines);
  }
  const preview = JSON.stringify(payload.data, null, 2)
    .split(/\r?\n/)
    .slice(0, maxLines);
  return preview;
}

function formatAgenticArtifact(payload, maxLines) {
  const artifact = payload.data || {};
  const lines = [];
  if (artifact.query?.text) lines.push(`Query: ${artifact.query.text}`);
  if (artifact.ui?.latestAssistantMessage?.content) {
    lines.push(`Answer: ${String(artifact.ui.latestAssistantMessage.content).replace(/\s+/g, " ").trim()}`);
  }
  if (Array.isArray(artifact.ui?.resultTables) && artifact.ui.resultTables.length > 0) {
    const table = artifact.ui.resultTables[0];
    lines.push(`Table: ${table.rowCount} rows · columns ${table.columns.join(", ")}`);
  }
  return lines.slice(0, maxLines);
}

function collectFiles(runArtifact, serviceFilter = null) {
  const files = [];
  for (const service of runArtifact.services || []) {
    if (serviceFilter && service.name !== serviceFilter) continue;
    for (const suite of service.suites || []) {
      for (const file of suite.files || []) {
        files.push({ service, suite, file });
      }
    }
  }
  return files;
}

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