///|
/// Aggregates token usage and call counts across many requests, so an
/// application can report cumulative consumption (and estimated cost).
pub struct UsageTracker {
  mut calls : Int
  mut prompt_tokens : Int
  mut completion_tokens : Int
  prompt_price_per_1k : Double
  completion_price_per_1k : Double
}

///|
/// Create a tracker. Prices default to 0 (cost reported as 0 until set).
pub fn UsageTracker::new(
  prompt_price_per_1k? : Double = 0.0,
  completion_price_per_1k? : Double = 0.0,
) -> UsageTracker {
  {
    calls: 0,
    prompt_tokens: 0,
    completion_tokens: 0,
    prompt_price_per_1k,
    completion_price_per_1k,
  }
}

///|
/// Record a usage entry (e.g. from a `ChatResponse.usage`).
pub fn UsageTracker::record(self : UsageTracker, usage : Usage) -> Unit {
  self.calls = self.calls + 1
  self.prompt_tokens = self.prompt_tokens + usage.prompt_tokens
  self.completion_tokens = self.completion_tokens + usage.completion_tokens
}

///|
/// Record the usage from a chat response, if it reported any.
pub fn UsageTracker::record_response(
  self : UsageTracker,
  response : ChatResponse,
) -> Unit {
  match response.usage {
    Some(u) => self.record(u)
    None => self.calls = self.calls + 1
  }
}

///|
/// The number of calls recorded.
pub fn UsageTracker::calls(self : UsageTracker) -> Int {
  self.calls
}

///|
/// The total tokens across all recorded calls.
pub fn UsageTracker::total_tokens(self : UsageTracker) -> Int {
  self.prompt_tokens + self.completion_tokens
}

///|
/// A `Usage` snapshot of the accumulated totals.
pub fn UsageTracker::snapshot(self : UsageTracker) -> Usage {
  {
    prompt_tokens: self.prompt_tokens,
    completion_tokens: self.completion_tokens,
    total_tokens: self.total_tokens(),
  }
}

///|
/// The estimated cost so far, in dollars, using the configured prices.
pub fn UsageTracker::cost(self : UsageTracker) -> Double {
  estimate_cost(
    self.prompt_tokens,
    self.completion_tokens,
    prompt_price_per_1k=self.prompt_price_per_1k,
    completion_price_per_1k=self.completion_price_per_1k,
  )
}

///|
/// Reset all counters to zero (prices are preserved).
pub fn UsageTracker::reset(self : UsageTracker) -> Unit {
  self.calls = 0
  self.prompt_tokens = 0
  self.completion_tokens = 0
}

///|
/// A one-line human-readable summary of the accumulated usage.
pub fn UsageTracker::summary(self : UsageTracker) -> String {
  "calls=\{self.calls} prompt=\{self.prompt_tokens} " +
  "completion=\{self.completion_tokens} total=\{self.total_tokens()}"
}