///|
/// Render one benchmark suite as a readable terminal report.
pub fn benchmark_suite_text(suite : BenchmarkSuite) -> String {
  let out : Array[String] = [
    "MoonBit VCD benchmark",
    "fixture: " + suite.fixture,
  ]
  for result in suite.results {
    out.push("- " + result.to_text())
  }
  out.join("\n")
}

///|
/// Render one result as a machine-readable JSON object.
pub fn benchmark_result_json(result : BenchmarkResult) -> String {
  "{\"name\":\"" +
  escape_text(result.name) +
  "\",\"iterations\":" +
  result.iterations.to_string() +
  ",\"input_chars\":" +
  result.input_chars.to_string() +
  ",\"parsed_traces\":" +
  result.parsed_traces.to_string() +
  ",\"observed_changes\":" +
  result.observed_changes.to_string() +
  ",\"checksum\":" +
  result.checksum.to_string() +
  "}"
}

///|
/// Render a complete benchmark suite as deterministic JSON.
pub fn benchmark_suite_json(suite : BenchmarkSuite) -> String {
  "{\"fixture\":\"" +
  escape_text(suite.fixture) +
  "\",\"results\":[" +
  suite.results.map(benchmark_result_json).join(",") +
  "]}"
}

///|
/// Render benchmark results as a Markdown table suitable for reports.
pub fn benchmark_suite_markdown(suite : BenchmarkSuite) -> String {
  let out : Array[String] = [
    "## Benchmark",
    "",
    "Fixture: `" + suite.fixture + "`",
    "",
    "| Operation | Iterations | Input chars | Parsed | Changes | Checksum |",
    "| --- | ---: | ---: | ---: | ---: | ---: |",
  ]
  for result in suite.results {
    out.push(
      "| " +
      result.name +
      " | " +
      result.iterations.to_string() +
      " | " +
      result.input_chars.to_string() +
      " | " +
      result.parsed_traces.to_string() +
      " | " +
      result.observed_changes.to_string() +
      " | " +
      result.checksum.to_string() +
      " |",
    )
  }
  out.join("\n")
}

///|
/// Return a compact CSV row for every benchmark operation.
pub fn benchmark_rows(suite : BenchmarkSuite) -> Array[String] {
  suite.results.map(fn(result) {
    suite.fixture +
    "," +
    result.name +
    "," +
    result.iterations.to_string() +
    "," +
    result.input_chars.to_string() +
    "," +
    result.parsed_traces.to_string() +
    "," +
    result.observed_changes.to_string() +
    "," +
    result.checksum.to_string()
  })
}

///|
/// Sum the stable checksums of all operations in a suite.
pub fn benchmark_checksum(suite : BenchmarkSuite) -> Int64 {
  suite.results.fold(init=0L, fn(total, result) { total + result.checksum })
}

///|
/// Return the number of source characters in a generated fixture.
pub fn fixture_size_report(signal_count : Int, time_count : Int) -> String {
  let fixture = synthetic_vcd(signal_count, time_count)
  "signals=" +
  Int::max(1, signal_count).to_string() +
  " times=" +
  Int::max(1, time_count).to_string() +
  " chars=" +
  fixture.length().to_string()
}

///|
/// Compare two benchmark runs by stable checksum and operation names.
pub fn benchmark_suite_compatible(
  left : BenchmarkSuite,
  right : BenchmarkSuite,
) -> Bool {
  if left.results.length() != right.results.length() {
    return false
  }
  for index in 0.. Double {
  if result.parsed_traces == 0 {
    0.0
  } else {
    result.observed_changes.to_double() / result.parsed_traces.to_double()
  }
}

///|
/// Produce a human-readable benchmark verdict for CI logs.
pub fn benchmark_verdict(suite : BenchmarkSuite) -> String {
  if suite.results.length() == 0 {
    "empty benchmark suite"
  } else if benchmark_checksum(suite) == 0L {
    "benchmark produced a zero checksum"
  } else {
    "ok checksum=" + benchmark_checksum(suite).to_string()
  }
}