///|
/// A reproducible benchmark measurement row.
pub struct BenchmarkMeasurement {
  name : String
  workload : String
  input_size : Int
  operations : Int
  checksum : String
  notes : String
}

///|
/// Aggregate throughput metadata for benchmark output.
pub struct BenchmarkReport {
  title : String
  toolchain : String
  measurements : Array[BenchmarkMeasurement]
  total_operations : Int
  total_input : Int
}

///|
/// Create an empty benchmark report.
pub fn BenchmarkReport::new(
  title : String,
  toolchain : String,
) -> BenchmarkReport {
  { title, toolchain, measurements: [], total_operations: 0, total_input: 0 }
}

///|
/// Add a measured workload row.
pub fn BenchmarkReport::add(
  self : BenchmarkReport,
  name : String,
  workload : String,
  input_size : Int,
  operations : Int,
  checksum : String,
  notes : String,
) -> BenchmarkReport {
  let measurements = self.measurements.copy()
  measurements.push({ name, workload, input_size, operations, checksum, notes })
  {
    title: self.title,
    toolchain: self.toolchain,
    measurements,
    total_operations: self.total_operations + operations.max(0),
    total_input: self.total_input + input_size.max(0),
  }
}

///|
/// Calculate a stable checksum for a numeric benchmark result.
pub fn benchmark_checksum(data : Array[Double]) -> String {
  waveform_checksum(data)
}

///|
/// Create a measurement row from an output trace.
pub fn benchmark_trace_measurement(
  name : String,
  workload : String,
  input : Trace,
  output : Trace,
  operations : Int,
  notes : String,
) -> BenchmarkMeasurement {
  {
    name,
    workload,
    input_size: input.npts(),
    operations,
    checksum: benchmark_checksum(output.data),
    notes,
  }
}

///|
/// Export benchmark measurements as CSV.
pub fn benchmark_report_to_csv(report : BenchmarkReport) -> String {
  let mut output = "name,workload,input_size,operations,checksum,notes\n"
  for measurement in report.measurements {
    output = output +
      measurement.name +
      "," +
      measurement.workload +
      "," +
      measurement.input_size.to_string() +
      "," +
      measurement.operations.to_string() +
      "," +
      measurement.checksum +
      "," +
      measurement.notes +
      "\n"
  }
  output
}

///|
/// Render a benchmark report in Markdown.
pub fn benchmark_report_to_markdown(report : BenchmarkReport) -> String {
  let mut output = "# " +
    report.title +
    "\n\nToolchain: `" +
    report.toolchain +
    "`\n\n"
  output += "| Workload | Input | Operations | Checksum |\n|---|---:|---:|---|\n"
  for measurement in report.measurements {
    output += "| " +
      measurement.workload +
      " | " +
      measurement.input_size.to_string() +
      " | " +
      measurement.operations.to_string() +
      " | `" +
      measurement.checksum +
      "` |\n"
  }
  output += "\nTotal input samples: " + report.total_input.to_string() + "\n"
  output += "Total operations: " + report.total_operations.to_string() + "\n"
  output
}

///|
/// Format benchmark report totals.
pub fn benchmark_report_summary(report : BenchmarkReport) -> String {
  "measurements=" +
  report.measurements.length().to_string() +
  " input=" +
  report.total_input.to_string() +
  " operations=" +
  report.total_operations.to_string()
}