import fs from "fs";
import path from "path";
import {
  applyTimingUpdates,
  createEmptyTimings,
  normalizeTimings,
} from "../timing/index.mjs";

const TIMINGS_FILENAME = "timings.json";
const RESULT_ARTIFACTS_DIRNAME = "artifacts";
const RESULT_LOGS_DIRNAME = "logs";
const RESULT_SETUP_DIRNAME = "setup";
const LIVE_ARTIFACT_FILENAME = "live.json";

export function writeRunArtifact(productDir, artifact) {
  const resultsDir = path.join(productDir, ".testkit", "results");
  fs.mkdirSync(resultsDir, { recursive: true });
  fs.writeFileSync(path.join(resultsDir, "latest.json"), JSON.stringify(artifact, null, 2));
  fs.rmSync(path.join(resultsDir, LIVE_ARTIFACT_FILENAME), { force: true });
}

export function writeLiveRunArtifact(productDir, artifact) {
  const resultsDir = path.join(productDir, ".testkit", "results");
  fs.mkdirSync(resultsDir, { recursive: true });
  fs.writeFileSync(path.join(resultsDir, LIVE_ARTIFACT_FILENAME), JSON.stringify(artifact, null, 2));
}

export function writeStatusArtifact(productDir, artifact) {
  fs.writeFileSync(
    path.join(productDir, "testkit.status.json"),
    `${JSON.stringify(artifact, null, 2)}\n`
  );
}

export function resetResultArtifacts(productDir) {
  fs.rmSync(path.join(productDir, ".testkit", "results", RESULT_ARTIFACTS_DIRNAME), {
    recursive: true,
    force: true,
  });
  fs.rmSync(path.join(productDir, ".testkit", "results", RESULT_LOGS_DIRNAME), {
    recursive: true,
    force: true,
  });
  fs.rmSync(path.join(productDir, ".testkit", "results", RESULT_SETUP_DIRNAME), {
    recursive: true,
    force: true,
  });
  fs.rmSync(path.join(productDir, ".testkit", "results", LIVE_ARTIFACT_FILENAME), {
    force: true,
  });
}

export function persistTaskArtifacts(productDir, task, emittedArtifacts) {
  if (!Array.isArray(emittedArtifacts) || emittedArtifacts.length === 0) return [];

  const artifactsDir = path.join(
    productDir,
    ".testkit",
    "results",
    RESULT_ARTIFACTS_DIRNAME,
    sanitizePathSegment(task.serviceName || "service")
  );
  fs.mkdirSync(artifactsDir, { recursive: true });

  return emittedArtifacts.map((artifact, index) => {
    const fileName = `task-${task.id}-${String(index + 1).padStart(2, "0")}-${sanitizePathSegment(artifact.name || "artifact")}.json`;
    const relativePath = path.join(
      ".testkit",
      "results",
      RESULT_ARTIFACTS_DIRNAME,
      sanitizePathSegment(task.serviceName || "service"),
      fileName
    );
    const absolutePath = path.join(productDir, relativePath);
    const payload = {
      schemaVersion: 1,
      source: "testkit-runtime-artifact",
      service: task.serviceName,
      suite: {
        key: task.suiteKey,
        name: task.suiteName,
        type: task.type,
      },
      file: task.file,
      taskId: task.id,
      index,
      name: artifact.name,
      kind: artifact.kind || null,
      summary: artifact.summary || null,
      contentType: artifact.contentType || "application/json",
      emittedAt: artifact.emittedAt || null,
      data: artifact.data,
    };
    fs.writeFileSync(absolutePath, `${JSON.stringify(payload, null, 2)}\n`);
    return {
      name: payload.name,
      kind: payload.kind,
      summary: payload.summary,
      contentType: payload.contentType,
      path: normalizePath(relativePath),
    };
  });
}

export function persistTaskOutputArtifacts(productDir, task, outputs) {
  if (!Array.isArray(outputs) || outputs.length === 0) return [];
  return persistTaskArtifacts(
    productDir,
    task,
    outputs
      .filter((entry) => typeof entry?.text === "string" && entry.text.trim().length > 0)
      .map((entry) => ({
        name: entry.name || "task-output",
        kind: entry.kind || "runtime.output",
        summary: entry.summary || summarizeOutput(entry.text),
        contentType: entry.contentType || "text/plain",
        emittedAt: entry.emittedAt || new Date().toISOString(),
        data: {
          stream: entry.stream || null,
          text: entry.text,
        },
      }))
  );
}

export function loadTimings(productDir) {
  const filePath = path.join(productDir, ".testkit", TIMINGS_FILENAME);
  if (!fs.existsSync(filePath)) {
    return createEmptyTimings();
  }

  try {
    return normalizeTimings(JSON.parse(fs.readFileSync(filePath, "utf8")));
  } catch {
    return createEmptyTimings();
  }
}

export function saveTimings(productDir, timings, updates) {
  if (updates.length === 0) return;
  const next = applyTimingUpdates(timings, updates);
  const rootDir = path.join(productDir, ".testkit");
  fs.mkdirSync(rootDir, { recursive: true });
  fs.writeFileSync(path.join(rootDir, TIMINGS_FILENAME), JSON.stringify(next, null, 2));
}

function sanitizePathSegment(value) {
  return String(value)
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9._-]+/g, "-")
    .replace(/^-+|-+$/g, "") || "artifact";
}

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

function summarizeOutput(text) {
  const firstLine = String(text)
    .split(/\r?\n/)
    .map((line) => line.trim())
    .find(Boolean);
  if (!firstLine) return "captured task output";
  return firstLine.slice(0, 120);
}
