///|
/// Results of a deterministic detector benchmark.
pub struct BenchmarkResult {
  name : String
  samples : Int
  passes : Int
  detections : Int
  first_detection : Int
  checksum : Double
  truth_count : Int
  metrics : ChangePointMetrics
}

///|
pub fn BenchmarkResult::empty(name : String) -> BenchmarkResult {
  {
    name,
    samples: 0,
    passes: 0,
    detections: 0,
    first_detection: -1,
    checksum: 0.0,
    truth_count: 0,
    metrics: ChangePointMetrics::empty(),
  }
}

///|
pub fn BenchmarkResult::summary(self : BenchmarkResult) -> String {
  "\{self.name}: samples=\{self.samples},passes=\{self.passes},detections=\{self.detections},first=\{self.first_detection},precision=\{self.metrics.precision},recall=\{self.metrics.recall},f1=\{self.metrics.f1},checksum=\{self.checksum}"
}

///|
fn record_detection(
  result : DetectionResult,
  detections : Array[Int],
  first : Int,
) -> Int {
  if result.changed {
    detections.push(result.index)
    if first < 0 {
      result.index
    } else {
      first
    }
  } else {
    first
  }
}

///|
pub fn benchmark_cusum(
  scenario : SignalScenario,
  rounds? : Int = 1,
) -> BenchmarkResult {
  let values = generate_signal(scenario)
  let detections : Array[Int] = []
  let mut first = -1
  let mut checksum = 0.0
  let mut passes = 0
  let count = if rounds < 1 { 1 } else { rounds }
  for round in 0.. BenchmarkResult {
  let values = generate_signal(scenario)
  let detections : Array[Int] = []
  let mut first = -1
  let mut checksum = 0.0
  let mut passes = 0
  let count = if rounds < 1 { 1 } else { rounds }
  for round in 0.. BenchmarkResult {
  let values = generate_signal(scenario)
  let detections : Array[Int] = []
  let mut first = -1
  let mut checksum = 0.0
  let mut passes = 0
  let count = if rounds < 1 { 1 } else { rounds }
  for round in 0.. Array[BenchmarkResult] {
  let scenario = SignalScenario::mean_and_variance(
    length=512,
    change_at=256,
    baseline=10.0,
    shift=2.0,
    noise=0.15,
    post_noise=0.7,
    seed=20260818L,
  )
  [
    benchmark_cusum(scenario, rounds~),
    benchmark_robust_z(scenario, rounds~),
    benchmark_ensemble(scenario, rounds~),
  ]
}

///|
pub fn benchmark_markdown(results : Array[BenchmarkResult]) -> String {
  let mut output = "| detector | samples | passes | detections | first detection | precision | recall | F1 | checksum |\n|---|---:|---:|---:|---:|---:|---:|---:|---:|\n"
  for result in results {
    output = output +
      "| \{result.name} | \{result.samples} | \{result.passes} | \{result.detections} | \{result.first_detection} | \{result.metrics.precision} | \{result.metrics.recall} | \{result.metrics.f1} | \{result.checksum} |\n"
  }
  output
}