///|
const ITERATIONS : Int = 2000

///|
fn sample_frame() -> @frame.Frame raise {
  @frame.Frame::fd_data(
    id=@frame.Id::extended(0x12345),
    bytes=Array::make(16, 0x5A),
    bit_rate_switch=true,
    error_state_indicator=false,
  )
}

///|
fn run_codec_benchmark(frame : @frame.Frame) -> String {
  let start = @bench.monotonic_clock_start()
  let mut checksum = 0
  for _ in 0.. [] }
    checksum += bits.length()
    ignore(@codec.decode(bits) catch { _ => frame })
  }
  let elapsed = @bench.monotonic_clock_end(start)
  "frame_round_trip iterations=" +
  ITERATIONS.to_string() +
  " elapsed_us=" +
  elapsed.to_string() +
  " checksum=" +
  checksum.to_string()
}

///|
fn run_signal_benchmark(frame : @frame.Frame) -> String {
  let signal = @signal.Signal::new(
    name="counter",
    start_bit=0,
    width=16,
    little_endian=true,
    signed=false,
    scale=1.0,
    offset=0.0,
    minimum=None,
    maximum=None,
  ) catch {
    _ => abort("signal setup failed")
  }
  let start = @bench.monotonic_clock_start()
  let mut checksum = 0.0
  for _ in 0.. frame }
    checksum += signal.decode(encoded) catch { _ => 0.0 }
  }
  let elapsed = @bench.monotonic_clock_end(start)
  "signal_pack_unpack iterations=" +
  ITERATIONS.to_string() +
  " elapsed_us=" +
  elapsed.to_string() +
  " checksum=" +
  checksum.to_string()
}

///|
fn run_log_benchmark(frame : @frame.Frame) -> String {
  let event = @sim.Event::new(
    tick=0,
    kind_code=0,
    node="bench",
    frame=Some(frame),
    detail="benchmark",
  )
  let events = Array::make(8, event)
  let start = @bench.monotonic_clock_start()
  let mut checksum = 0
  for _ in 0.. 0 }
  }
  let elapsed = @bench.monotonic_clock_end(start)
  "json_round_trip iterations=" +
  ITERATIONS.to_string() +
  " elapsed_us=" +
  elapsed.to_string() +
  " checksum=" +
  checksum.to_string()
}

///|
fn run_bus_benchmark(frame : @frame.Frame) -> String {
  let bus = @sim.Bus::new()
  bus.attach(name="bench", capacity=ITERATIONS) catch {
    _ => return "bus_setup_failed"
  }
  let start = @bench.monotonic_clock_start()
  for _ in 0.. ()
    }
    ignore(bus.step() catch { _ => [] })
  }
  let elapsed = @bench.monotonic_clock_end(start)
  "virtual_bus_steps iterations=" +
  ITERATIONS.to_string() +
  " elapsed_us=" +
  elapsed.to_string() +
  " tick=" +
  bus.logical_tick().to_string()
}

///|
fn main {
  let frame = sample_frame() catch { _ => return }
  println("moonbit-canbus benchmark; iterations=" + ITERATIONS.to_string())
  println(run_codec_benchmark(frame))
  println(run_signal_benchmark(frame))
  println(run_log_benchmark(frame))
  println(run_bus_benchmark(frame))
}