// moon-frequency-sketch CLI
// ==========================
// Demonstrates all sketch data structures with a simulated API monitoring scenario.

///|
fn main {
  println("moon-frequency-sketch CLI v0.2.0")
  println("")
  demo_stream()
  demo_telemetry()
}

///|
/// Simulated API endpoint monitoring demo.
fn demo_stream() -> Unit {
  println("=== Demo: API Endpoint Frequency Monitor ===")
  println("")
  let cms = @cms.CountMinSketch::new(5, 1000)
  let ss = @topk.SpaceSaving::new(20)
  let bf = @bloomfilter.BloomFilter::from_params(500, 0.01)
  let sw = @window.SlidingWindow::new(6, 4, 200)
  let endpoints = [
    "/api/users", "/api/products", "/api/orders", "/api/search", "/api/health", "/api/auth/login",
    "/api/auth/logout", "/api/products/featured", "/api/users/profile", "/api/reports",
  ]
  let weights = [300L, 200L, 150L, 100L, 50L, 80L, 40L, 60L, 30L, 20L]
  let mut total_calls = 0L
  let mut i = 0
  while i < endpoints.length() {
    let ep = endpoints[i]
    let w = weights[i]
    cms.add_str(ep, w)
    ss.add_count(ep, w)
    bf.add_str(ep)
    sw.add_str(ep, w)
    total_calls = total_calls + w
    i = i + 1
  }
  println("Total API calls tracked: " + total_calls.to_string())
  println("CMS: " + cms.summary())
  println("")
  // Report Top-5 by Space-Saving
  println("--- Top 5 Endpoints (Space-Saving) ---")
  let top5 = ss.top_k(5)
  i = 0
  while i < top5.length() {
    let pct = top5[i].count.to_double() / total_calls.to_double() * 100.0
    println(
      "  " +
      (i + 1).to_string() +
      ". " +
      top5[i].key +
      " count=" +
      top5[i].count.to_string() +
      " calls (" +
      pct.to_string() +
      "%)",
    )
    i = i + 1
  }
  println("")
  // CMS verification
  println("--- CMS Frequency Verification ---")
  i = 0
  while i < endpoints.length() {
    let est = cms.estimate_str(endpoints[i])
    let true_val = weights[i]
    let over = est - true_val
    println(
      "  " +
      endpoints[i] +
      " : true=" +
      true_val.to_string() +
      " est=" +
      est.to_string() +
      " over=" +
      over.to_string(),
    )
    i = i + 1
  }
  println("")
  // Bloom filter membership check
  println("--- Bloom Filter Membership ---")
  let test_keys = ["/api/users", "/api/unknown_endpoint", "/api/products"]
  i = 0
  while i < test_keys.length() {
    let present = bf.contains_str(test_keys[i])
    let status = if present { "possibly present" } else { "definitely absent" }
    println("  " + test_keys[i] + " -> " + status)
    i = i + 1
  }
  println("")
  // Sliding window
  println("--- Sliding Window (6 buckets) ---")
  i = 0
  while i < endpoints.length() {
    let sw_est = sw.estimate_str(endpoints[i])
    println("  " + endpoints[i] + " window estimate: " + sw_est.to_string())
    i = i + 1
  }
  println("")
  // Count Sketch comparison
  println("--- Count Sketch (Unbiased Estimator) ---")
  let cs = @countsketch.CountSketch::new(7, 500)
  i = 0
  while i < endpoints.length() {
    cs.add_str(endpoints[i], weights[i])
    i = i + 1
  }
  i = 0
  while i < 3 {
    let est = cs.estimate_str(endpoints[i])
    println(
      "  " +
      endpoints[i] +
      " CS estimate: " +
      est.to_string() +
      " (true: " +
      weights[i].to_string() +
      ")",
    )
    i = i + 1
  }
  println("")
  // Distributed merge demo
  println("--- Distributed Merge Demo ---")
  let shard1 = @cms.CountMinSketch::new(5, 1000)
  let shard2 = @cms.CountMinSketch::new(5, 1000)
  shard1.add_str("/api/users", 150L)
  shard2.add_str("/api/users", 150L)
  match @cms.cms_merge(shard1, shard2) {
    Ok(merged) =>
      println(
        "  Merged /api/users estimate: " +
        merged.estimate_str("/api/users").to_string() +
        " (expected 300)",
      )
    Err(_) => println("  Merge failed")
  }
  println("")
  println("=== CLI Demo Complete ===")
}

///|
/// Combined telemetry facade demo for an API monitoring workflow.
fn demo_telemetry() -> Unit {
  println("")
  println("=== Demo: Unified Telemetry Monitor ===")
  let monitor = @telemetry.Monitor::new(5, 4, 5, 500, 10, 100).unwrap()
  for i in 0..<100 {
    let endpoint = if i % 5 == 0 { "/api/search" } else { "/api/users" }
    let entity = "user-" + (i % 20).to_string()
    let status = if i % 17 == 0 { 500 } else { 200 }
    let latency = if endpoint == "/api/search" {
      80.0 + (i % 7).to_double()
    } else {
      12.0 + (i % 5).to_double()
    }
    monitor
    .observe(@telemetry.Event::new(endpoint, entity, status, latency, 256L))
    .unwrap()
  }
  let report = monitor.report()
  println("  total events: " + report.total_events.to_string())
  println("  error rate: " + report.error_rate.to_string())
  println("  unique entities: " + report.unique_entities.to_string())
  match report.latency_p95 {
    Some(value) => println("  latency p95: " + value.to_string() + " ms")
    None => println("  latency p95: unavailable")
  }
  println("  window events: " + report.window_total.to_string())
}