///|
pub(all) struct Sample {
  timestamp : Double
  value : Double
} derive(Eq, @debug.Debug)

///|
pub(all) struct Series {
  metric : String
  labels : LabelSet
  samples : Array[Sample]
}

///|
pub fn Series::new(
  metric : String,
  labels : LabelSet,
  samples : Array[Sample],
) -> Series {
  let sorted = samples.copy()
  sorted.sort_by((left, right) => left.timestamp.compare(right.timestamp))
  { metric, labels: labels.set("__name__", metric), samples: sorted, }
}

///|
/// One evaluated point in an instant vector.
pub(all) struct Point {
  labels : LabelSet
  value : Double
} derive(Eq, @debug.Debug)

///|
/// One series in a range vector.
pub(all) struct RangeSeries {
  labels : LabelSet
  samples : Array[Sample]
} derive(Eq, @debug.Debug)

///|
/// The four PromQL value kinds implemented by this package.
pub(all) enum Value {
  Scalar(Double)
  StringValue(String)
  Instant(Array[Point])
  Range(Array[RangeSeries])
} derive(Eq, @debug.Debug)

///|
pub fn Value::kind(self : Value) -> String {
  match self {
    Scalar(_) => "scalar"
    StringValue(_) => "string"
    Instant(_) => "instant vector"
    Range(_) => "range vector"
  }
}

///|
pub fn Point::to_string(self : Point) -> String {
  "\{self.labels.to_string()} => \{self.value}"
}

///|
pub fn Value::to_string(self : Value) -> String {
  match self {
    Scalar(value) => value.to_string()
    StringValue(value) => value
    Instant(points) => {
      let builder = StringBuilder()
      builder.write_string("[")
      for i, point in points {
        if i > 0 {
          builder.write_string(", ")
        }
        builder.write_string(point.to_string())
      }
      builder.write_string("]")
      builder.to_string()
    }
    Range(series) => {
      let builder = StringBuilder()
      builder.write_string("[")
      for i, item in series {
        if i > 0 {
          builder.write_string(", ")
        }
        builder.write_string(item.labels.to_string())
        builder.write_string(" (")
        builder.write_string(item.samples.length().to_string())
        builder.write_string(" samples)")
      }
      builder.write_string("]")
      builder.to_string()
    }
  }
}