// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// Anything a registry can collect: a metric, a family of metrics, or a custom
/// collector's contribution. Implement this to plug a new metric shape into a
/// registry without changing the registry.
pub(open) trait Metric {
  fn kind(Self) -> Kind
  fn points(Self) -> Array[Point]
}

///|
/// A monotonically increasing count. `inc` refuses a negative step because a
/// counter that goes down is a gauge.
pub struct Counter {
  priv mut value : Double
  priv mut created : Double?
  priv mut exemplar : Exemplar?
}

///|
/// A counter at zero. `created` records when the series came into existence, for
/// the `_created` series OpenMetrics exposes.
pub fn Counter::new(created? : Double) -> Counter {
  { value: 0.0, created, exemplar: None, }
}

///|
/// Increase the counter by `by`, keeping `exemplar` as the latest exemplar.
pub fn Counter::inc(
  self : Counter,
  by~ : Double = 1.0,
  exemplar? : Exemplar,
) -> Unit raise Refused {
  if by < 0.0 {
    raise Refused("counter can only increase, got " + by.to_string())
  }
  self.accrue(by)
  match exemplar {
    Some(e) => self.exemplar = Some(e)
    None => ()
  }
}

///|
fn Counter::accrue(self : Counter, by : Double) -> Unit {
  self.value = self.value + by
}

///|
/// Restart the counter at zero, optionally dating the reset as a new creation
/// time. Use this when a logical process restarts without restarting the
/// program.
pub fn Counter::reset(self : Counter, created? : Double) -> Unit {
  self.value = 0.0
  match created {
    Some(c) => self.created = Some(c)
    None => ()
  }
}

///|
/// The current count.
pub fn Counter::get(self : Counter) -> Double {
  self.value
}

///|
pub impl Metric for Counter with fn kind(_self) {
  Kind::Counter
}

///|
pub impl Metric for Counter with fn points(self) {
  let exemplars : Array[Exemplar] = match self.exemplar {
    Some(e) => [e]
    None => []
  }
  [
    {
      labels: [],
      value: Number(self.value),
      timestamp: None,
      created: self.created,
      exemplars,
    },
  ]
}

///|
pub extend Counter with Metric::{kind, points}