///|
fn print_decision(label : String, decision : @quota.Decision) -> Unit {
  println("\{label}=\{decision.to_json()}")
}

///|
fn main {
  let engine = @quota.QuotaEngine::new()
  ignore(engine.add_limit(@quota.LimitSpec::new("tokens", 4, 2, 1000L, 2)))
  ignore(engine.add_limit(@quota.LimitSpec::new("smooth", 2, 2, 1000L, 0)))

  let alice = @quota.QuotaKey::new("tenant-a", "alice", "llm")
  let tenant = @quota.QuotaKey::new("tenant-a", "all", "llm")
  ignore(engine.add_link(@quota.QuotaLink::new(alice, tenant, "tokens", 1)))
  ignore(engine.add_subject("free", 1))
  ignore(engine.add_subject("pro", 4))
  ignore(engine.record_usage("free", 3))
  ignore(engine.record_usage("pro", 4))

  print_decision(
    "token_bucket",
    engine.check_token_bucket(alice, "tokens", 0L, 2),
  )
  print_decision("window", engine.check_window(alice, "tokens", 0L, 1))
  print_decision("gcra", engine.check_gcra(alice, "smooth", 0L, 1))
  print_decision("hierarchy", engine.check_hierarchy(alice, "tokens", 0L, 1))
  let transaction = engine.check_atomic_token_buckets(
    [
      @quota.QuotaCharge::new(alice, "tokens", 1),
      @quota.QuotaCharge::new(tenant, "tokens", 1),
    ],
    0L,
  )
  println("atomic=\{transaction.to_json()}")

  let batch = engine.check_many_token_bucket("tokens", [
    @quota.EvaluationInput::new(alice, 0L, 1),
    @quota.EvaluationInput::new(alice, 0L, 1),
    @quota.EvaluationInput::new(alice, 0L, 1),
  ])
  println("batch=\{batch.to_json()}")
  println("next_fair_subject=\{engine.next_fair_subject()}")
  println("stats=\{engine.stats().to_json()}")
  println("issues=\{engine.validate().length()}")
  println(engine.to_json())
}