import { mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
import { join, relative } from "node:path";

import type { InvalidArticleSample, RunSummary, SampleResult } from "./types";

interface AggregateInput {
  startedAt: string;
  finishedAt: string;
  provider: string;
  model: string;
  baseURL: string;
  reportDir: string;
  samples: SampleResult[];
  invalidSamples: InvalidArticleSample[];
}

export function writeSampleResult(reportDir: string, result: SampleResult) {
  const sampleDir = join(reportDir, "samples", result.slug);
  mkdirSync(sampleDir, { recursive: true });
  writeFileSync(
    join(sampleDir, "result.json"),
    `${JSON.stringify(result, null, 2)}\n`,
  );
}

export function readSampleResults(reportDir: string): SampleResult[] {
  const samplesDir = join(reportDir, "samples");
  try {
    return readdirSync(samplesDir, { withFileTypes: true })
      .filter((entry) => entry.isDirectory())
      .map((entry) => join(samplesDir, entry.name, "result.json"))
      .map(
        (filePath) => JSON.parse(readFileSync(filePath, "utf8")) as SampleResult,
      )
      .sort((left, right) => left.file.localeCompare(right.file));
  } catch {
    return [];
  }
}

export function aggregateSummary(input: AggregateInput): RunSummary {
  const passed = input.samples.filter((sample) => sample.status === "passed").length;
  const failed = input.samples.filter((sample) => sample.status === "failed").length;
  const skipped =
    input.samples.filter((sample) => sample.status === "skipped").length +
    input.invalidSamples.length;

  return {
    started_at: input.startedAt,
    finished_at: input.finishedAt,
    mode: "live",
    provider: input.provider,
    model: input.model,
    base_url: input.baseURL,
    report_dir: input.reportDir,
    totals: { passed, failed, skipped },
    samples: input.samples,
    invalid_samples: input.invalidSamples,
  };
}

export function writeSummaryFiles(reportDir: string, summary: RunSummary) {
  mkdirSync(reportDir, { recursive: true });
  writeFileSync(
    join(reportDir, "summary.json"),
    `${JSON.stringify(summary, null, 2)}\n`,
  );
  writeFileSync(join(reportDir, "summary.md"), renderSummaryMarkdown(summary));
}

export function redactSensitiveText(
  text: string,
  secrets: Array<string | undefined>,
) {
  let redacted = text
    .replace(/(x-api-key:\s*)([^\s]+)/gi, "$1[REDACTED]")
    .replace(/(authorization:\s*bearer\s+)([^\s]+)/gi, "$1[REDACTED]")
    .replace(
      /((?:DEEPSEEK|OPENAI|API)_?[A-Z_]*KEY=)"?([^"\s]+)"?/g,
      '$1"[REDACTED]"',
    );

  for (const secret of secrets) {
    if (!secret) continue;
    redacted = redacted.split(secret).join("[REDACTED]");
  }

  return redacted;
}

function renderSummaryMarkdown(summary: RunSummary) {
  const lines = [
    "# GEO 样例文章 E2E 测试报告",
    "",
    `- 模式：${summary.mode}`,
    `- Provider：${summary.provider}`,
    `- Model：${summary.model}`,
    `- Base URL：${summary.base_url}`,
    `- 报告目录：${summary.report_dir}`,
    `- 结果：通过 ${summary.totals.passed}，失败 ${summary.totals.failed}，跳过 ${summary.totals.skipped}`,
    "",
    "| 样例 | 状态 | QA | 耗时 | 失败分类 |",
    "| --- | --- | --- | ---: | --- |",
    ...summary.samples
      .map((sample) =>
        [
          sample.name,
          sample.status,
          sample.qa_status ?? "",
          `${Math.round(sample.duration_ms / 1000)}s`,
          sample.failure_category ?? "",
        ].join(" | "),
      )
      .map((row) => `| ${row} |`),
  ];

  if (summary.invalid_samples.length > 0) {
    lines.push("", "## 无效样例", "");
    for (const sample of summary.invalid_samples) {
      lines.push(`- ${sample.fileName}: ${sample.reason}`);
    }
  }

  lines.push("");
  return lines.join("\n");
}

export function relativeArtifactPath(reportDir: string, artifactPath: string) {
  return relative(reportDir, artifactPath);
}
