// ============================================================
// Deterministic benchmark and regression harness
//
// This deliberately measures logical work (ticks and outcomes), not wall
// clock time. It is portable across wasm-gc, JS, and native backends and is
// therefore suitable for CI regression checks and reproducible reports.
// ============================================================

///|
/// Counts the observable outcomes of one benchmark run.
pub struct BenchmarkResult {
  name : String
  frames : Int
  successes : Int
  failures : Int
  running : Int
}

///|
/// Execute exactly `frames` ticks and collect outcome counts.
pub fn benchmark_node(
  name : String,
  root : Node,
  bb : Blackboard,
  frames : Int,
) -> BenchmarkResult {
  let mut successes = 0
  let mut failures = 0
  let mut running = 0
  let limit = if frames > 0 { frames } else { 0 }
  let mut i = 0
  while i < limit {
    match root.tick(bb) {
      Status::BTSuccess => successes = successes + 1
      Status::BTFailure => failures = failures + 1
      Status::BTRunning => running = running + 1
    }
    i = i + 1
  }
  { name, frames: limit, successes, failures, running }
}

///|
/// Access the scenario name.
pub fn BenchmarkResult::name(self : BenchmarkResult) -> String {
  self.name
}

///|
/// Access the number of executed frames.
pub fn BenchmarkResult::frames(self : BenchmarkResult) -> Int {
  self.frames
}

///|
/// Number of successful frames.
pub fn BenchmarkResult::successes(self : BenchmarkResult) -> Int {
  self.successes
}

///|
/// Number of failed frames.
pub fn BenchmarkResult::failures(self : BenchmarkResult) -> Int {
  self.failures
}

///|
/// Number of running frames.
pub fn BenchmarkResult::running(self : BenchmarkResult) -> Int {
  self.running
}

///|
/// Return a stable CSV row for benchmark archives.
pub fn BenchmarkResult::to_csv(self : BenchmarkResult) -> String {
  "\{self.name},\{self.frames},\{self.successes},\{self.failures},\{self.running}"
}

///|
/// Return a compact human-readable summary.
pub fn BenchmarkResult::summary(self : BenchmarkResult) -> String {
  "\{self.name}: frames=\{self.frames}, success=\{self.successes}, failure=\{self.failures}, running=\{self.running}"
}

///|
/// Build a deterministic mixed workload used by examples and CI.
pub fn benchmark_workload() -> Node {
  sequence_node([
    condition_node(fn(bb) { bb.get_bool("enabled").unwrap_or(false) }),
    stable_success_node(
      action_node(fn(bb) {
        let n = bb.get_int("work").unwrap_or(0)
        bb.set_int("work", n + 1)
        Status::BTSuccess
      }),
      2,
    ),
    cooldown_node(action_node(fn(_) { Status::BTSuccess }), 1),
  ])
}