///|
/// moon-agent microbenchmarks.
///
/// Run with: moon run bench --target 
///
/// Uses `moonbitlang/core/bench` (auto-sized batches, winsorized stats).
/// Each hot path must stay under a generous per-operation threshold
/// (1 ms), so the benchmark only fails on real performance regressions
/// (e.g. accidental quadratic loops), not on slow CI runners.
///
/// Results are printed both human-readably and as JSON (via
/// `dump_summaries`), giving an inspectable baseline.

///|
/// Print each summary and return whether all means stay under threshold.
fn print_and_check_summaries(json_str : String, threshold_us : Double) -> Bool {
  let parsed = @json.parse(json_str) catch { _ => return false }
  let mut ok = true
  match parsed {
    Json::Array(items) =>
      for item in items {
        match item {
          Json::Object(map) => {
            let name = match map.get("name") {
              Some(Json::String(n)) => n
              _ => "?"
            }
            let mean = match map.get("mean") {
              Some(Json::Number(n, ..)) => n
              _ => 0.0
            }
            println(name + ": " + mean.to_string() + " us/op")
            if mean > threshold_us {
              println(
                "  FAILED: exceeds threshold " +
                threshold_us.to_string() +
                " us",
              )
              ok = false
            }
          }
          _ => ()
        }
      }
    _ => ()
  }
  ok
}

///|
fn main {
  // Sink keeps results alive so the optimizer cannot remove the work.
  let sink : Array[Int] = [0]
  let b = @core_bench.Bench()

  // 1. Prompt template rendering
  let prompt = @prompts.ChatPromptTemplate::new()
    |> @prompts.ChatPromptTemplate::with_user(
      "你是一个乐于助人的助手,请回答:{topic}",
    )
  let vars : Map[String, String] = Map([])
  vars["topic"] = "MoonBit"
  b.bench(name="PromptTemplate.render", fn() {
    let messages = prompt.render(vars)
    sink[0] = sink[0] + messages.length()
  })

  // 2. Calculator evaluation (public run path, includes JSON parsing)
  let calc_input = @json.parse("{\"expression\":\"15*23+100\"}") catch {
    _ => Json::null()
  }
  let calculator = @tools.CalculatorTool::new()
  b.bench(name="CalculatorTool.run", fn() {
    let out = calculator.run(calc_input)
    sink[0] = sink[0] + out.length()
  })

  // 3. Response cache set/get
  let cache = @cache.InMemoryCache::new(max_entries=100000)
  b.bench(name="InMemoryCache.set_get", fn() {
    cache.set("key", "value")
    match cache.get("key") {
      Some(v) => sink[0] = sink[0] + v.length()
      None => ()
    }
  })

  // 4. Tool registry dispatch
  let registry = @llm_tools.ToolRegistry::new()
  registry.register("echo", "Echo input", Json::null(), fn(
    input : Json,
  ) -> String {
    input.stringify()
  })
  b.bench(name="ToolRegistry.execute", fn() {
    let (out, _is_error) = registry.execute("echo", calc_input)
    sink[0] = sink[0] + out.length()
  })

  b.keep(sink[0])

  let json_str = b.dump_summaries()
  println("Benchmark summaries: " + json_str)
  let ok = print_and_check_summaries(json_str, 1000.0)
  if !ok {
    panic()
  }
  println("All benchmarks passed.")
}