import fs from "fs";
import path from "path";

const HISTORY_SCHEMA_VERSION = 1;
const HISTORY_DIRNAME = "history";
const TEST_HISTORY_FILENAME = "tests.json";

export function historyFilePath(productDir) {
  return path.join(productDir, ".testkit", HISTORY_DIRNAME, TEST_HISTORY_FILENAME);
}

export function createEmptyHistory() {
  return {
    version: HISTORY_SCHEMA_VERSION,
    tests: {},
  };
}

export function loadHistory(productDir) {
  const filePath = historyFilePath(productDir);
  if (!fs.existsSync(filePath)) {
    return createEmptyHistory();
  }

  try {
    const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
    return normalizeHistory(parsed);
  } catch {
    return createEmptyHistory();
  }
}

export function saveHistory(productDir, history) {
  const filePath = historyFilePath(productDir);
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, `${JSON.stringify(normalizeHistory(history), null, 2)}\n`);
}

export function updateHistoryFromRunArtifact(history, runArtifact, recordedAt = null) {
  const normalized = normalizeHistory(history);
  const seenAt = recordedAt || runArtifact?.generatedAt || new Date().toISOString();

  for (const service of runArtifact?.services || []) {
    for (const suite of service.suites || []) {
      for (const file of suite.files || []) {
        const id = buildHistoryTestId(service.name, suite.type, file.path);
        const existing = normalized.tests[id];
        const next = existing
          ? { ...existing }
          : {
              id,
              path: file.path,
              service: service.name,
              suiteName: suite.name,
              selectionType: suite.type,
              framework: normalizeArtifactFramework(suite.framework),
              firstSeenAt: seenAt,
              lastSeenAt: seenAt,
              lastRunAt: seenAt,
              runCount: 0,
              passCount: 0,
              failCount: 0,
              skipCount: 0,
              notRunCount: 0,
              avgDurationMs: 0,
              durationCount: 0,
              lastStatus: null,
            };

        next.path = file.path;
        next.service = service.name;
        next.suiteName = suite.name;
        next.selectionType = suite.type;
        next.framework = normalizeArtifactFramework(suite.framework);
        next.lastSeenAt = seenAt;
        next.lastRunAt = seenAt;
        next.runCount += 1;
        next.lastStatus = file.status;

        if (file.status === "passed") next.passCount += 1;
        else if (file.status === "failed") next.failCount += 1;
        else if (file.status === "skipped") next.skipCount += 1;
        else next.notRunCount += 1;

        if (Number(file.durationMs || 0) > 0 && file.status !== "skipped" && file.status !== "not_run") {
          const durationCount = Number(next.durationCount || 0) + 1;
          next.avgDurationMs = Math.max(
            1,
            Math.round(
              ((Number(next.avgDurationMs || 0) * Number(next.durationCount || 0)) + Number(file.durationMs || 0)) /
                durationCount
            )
          );
          next.durationCount = durationCount;
        }

        normalized.tests[id] = next;
      }
    }
  }

  return normalized;
}

export function summarizeHistoryForFiles(history, files = []) {
  const normalized = normalizeHistory(history);
  const byId = new Map();
  for (const file of files) {
    const entry = normalized.tests[file.id] || normalized.tests[buildHistoryTestId(file.service, file.selectionType, file.path)];
    if (!entry) continue;
    byId.set(file.id, {
      firstSeenAt: entry.firstSeenAt || null,
      lastSeenAt: entry.lastSeenAt || null,
      lastRunAt: entry.lastRunAt || null,
      runCount: Number(entry.runCount || 0),
      passCount: Number(entry.passCount || 0),
      failCount: Number(entry.failCount || 0),
      skipCount: Number(entry.skipCount || 0),
      avgDurationMs: Number(entry.avgDurationMs || 0),
      lastStatus: entry.lastStatus || null,
    });
  }
  return byId;
}

export function buildHistoryTestId(serviceName, selectionType, filePath) {
  return [serviceName, selectionType, normalizePath(filePath)].join("|");
}

function normalizeHistory(parsed) {
  const tests = {};
  for (const [id, entry] of Object.entries(parsed?.tests || {})) {
    tests[id] = {
      id,
      path: normalizePath(entry.path || ""),
      service: String(entry.service || ""),
      suiteName: String(entry.suiteName || ""),
      selectionType: String(entry.selectionType || ""),
      framework: normalizeArtifactFramework(entry.framework || "k6"),
      firstSeenAt: entry.firstSeenAt || null,
      lastSeenAt: entry.lastSeenAt || null,
      lastRunAt: entry.lastRunAt || null,
      runCount: Number(entry.runCount || 0),
      passCount: Number(entry.passCount || 0),
      failCount: Number(entry.failCount || 0),
      skipCount: Number(entry.skipCount || 0),
      notRunCount: Number(entry.notRunCount || 0),
      avgDurationMs: Number(entry.avgDurationMs || 0),
      durationCount: Number(entry.durationCount || 0),
      lastStatus: entry.lastStatus || null,
    };
  }
  return {
    version: HISTORY_SCHEMA_VERSION,
    tests,
  };
}

function normalizeArtifactFramework(value) {
  if (value === "default") return "k6";
  return value || "k6";
}

function normalizePath(filePath) {
  return String(filePath).split(path.sep).join("/").replace(/^\.\/+/, "");
}
