///|
/// Metric family kinds used by immutable gather/export contracts.
pub(all) enum FamilyType {
  CounterFamily
  GaugeFamily
  HistogramFamily
} derive(Debug, Eq)

///|
/// One detached scalar sample.  Label order is canonicalized by
/// `Registry::gather` before an exporter receives the snapshot.
pub(all) struct ScalarSampleSnapshot {
  labels : Array[@metric.Label]
  value : Double
} derive(Debug, Eq)

///|
pub fn scalar_sample(
  labels : Array[@metric.Label],
  value : Double,
) -> ScalarSampleSnapshot {
  { labels: labels.copy(), value }
}

///|
/// One detached histogram sample.
pub(all) struct HistogramSampleSnapshot {
  labels : Array[@metric.Label]
  value : @metric.HistogramSnapshot
} derive(Debug, Eq)

///|
fn copy_histogram_snapshot(
  value : @metric.HistogramSnapshot,
) -> @metric.HistogramSnapshot {
  {
    boundaries: value.boundaries.copy(),
    cumulative_counts: value.cumulative_counts.copy(),
    count: value.count,
    sum: value.sum,
  }
}

///|
pub fn histogram_sample(
  labels : Array[@metric.Label],
  value : @metric.HistogramSnapshot,
) -> HistogramSampleSnapshot {
  { labels: labels.copy(), value: copy_histogram_snapshot(value) }
}

///|
/// A complete, detached metric family.  Exactly one of the sample arrays is
/// non-empty for a non-empty family: scalar for counter/gauge, histogram for
/// histogram.  Empty families are valid for custom collectors.
pub(all) struct FamilySnapshot {
  name : String
  help : String
  unit : String?
  family_type : FamilyType
  scalar_samples : Array[ScalarSampleSnapshot]
  histogram_samples : Array[HistogramSampleSnapshot]
} derive(Debug, Eq)

///|
pub fn FamilySnapshot::scalar(
  name : String,
  help : String,
  family_type : FamilyType,
  samples : Array[ScalarSampleSnapshot],
  unit : String?,
) -> FamilySnapshot {
  {
    name,
    help,
    unit,
    family_type,
    scalar_samples: samples.copy(),
    histogram_samples: [],
  }
}

///|
pub fn FamilySnapshot::histogram(
  name : String,
  help : String,
  samples : Array[HistogramSampleSnapshot],
  unit : String?,
) -> FamilySnapshot {
  {
    name,
    help,
    unit,
    family_type: HistogramFamily,
    scalar_samples: [],
    histogram_samples: samples.copy(),
  }
}

///|
/// Exporters consume this detached value rather than mutable metric objects.
pub(all) struct GatherSnapshot {
  families : Array[FamilySnapshot]
} derive(Debug, Eq)

///|
pub fn GatherSnapshot::families(self : GatherSnapshot) -> Array[FamilySnapshot] {
  self.families.copy()
}