///|
/// Integer statistics for deterministic solver and application telemetry.
///
/// Metrics avoid floating-point dependence so benchmark snapshots remain
/// reproducible across native, wasm, and wasm-gc targets. Percentage and
/// correlation helpers use explicit scale factors documented by their names.
pub struct IntegerSummary {
  count : Int
  total : Int
  minimum : Int
  maximum : Int
  median : Int
  mean : Int
}

///|
/// Summarize an integer sample.
pub fn integer_summary(values : Array[Int]) -> IntegerSummary {
  if values.length() == 0 {
    return { count: 0, total: 0, minimum: 0, maximum: 0, median: 0, mean: 0 }
  }
  let sorted = values.copy()
  sort_integers(sorted)
  let mut total = 0
  for value in sorted {
    total += value
  }
  {
    count: sorted.length(),
    total,
    minimum: sorted[0],
    maximum: sorted[sorted.length() - 1],
    median: sorted[sorted.length() / 2],
    mean: total / sorted.length(),
  }
}

///|
/// Read sample count.
pub fn IntegerSummary::count(self : IntegerSummary) -> Int {
  self.count
}

///|
/// Read total.
pub fn IntegerSummary::total(self : IntegerSummary) -> Int {
  self.total
}

///|
/// Read minimum.
pub fn IntegerSummary::minimum(self : IntegerSummary) -> Int {
  self.minimum
}

///|
/// Read maximum.
pub fn IntegerSummary::maximum(self : IntegerSummary) -> Int {
  self.maximum
}

///|
/// Read median.
pub fn IntegerSummary::median(self : IntegerSummary) -> Int {
  self.median
}

///|
/// Read integer mean.
pub fn IntegerSummary::mean(self : IntegerSummary) -> Int {
  self.mean
}

///|
/// Return a stable summary line.
pub fn IntegerSummary::describe(self : IntegerSummary) -> String {
  "count=\{self.count}, total=\{self.total}, min=\{self.minimum}, max=\{self.maximum}, median=\{self.median}, mean=\{self.mean}"
}

///|
/// Sort an integer array in ascending order.
pub fn sort_integers(values : Array[Int]) -> Unit {
  for left in 0.. Int {
  let mut result = 0
  for value in values {
    result += value
  }
  result
}

///|
/// Return the integer mean or zero for an empty sample.
pub fn integer_mean(values : Array[Int]) -> Int {
  if values.length() == 0 {
    0
  } else {
    integer_sum(values) / values.length()
  }
}

///|
/// Return population variance using integer division.
pub fn integer_variance(values : Array[Int]) -> Int {
  if values.length() == 0 {
    return 0
  }
  let mean = integer_mean(values)
  let mut total = 0
  for value in values {
    let delta = value - mean
    total += delta * delta
  }
  total / values.length()
}

///|
/// Return an integer square root.
pub fn integer_sqrt(value : Int) -> Int {
  if value <= 0 {
    return 0
  }
  let mut low = 1
  let mut high = if value < 46340 * 46340 { value } else { 46340 }
  let mut result = 0
  while low <= high {
    let middle = (low + high) / 2
    if middle <= value / middle {
      result = middle
      low = middle + 1
    } else {
      high = middle - 1
    }
  }
  result
}

///|
/// Return population standard deviation as an integer.
pub fn integer_stddev(values : Array[Int]) -> Int {
  integer_sqrt(integer_variance(values))
}

///|
/// Return a percentile using nearest-rank selection.
pub fn integer_percentile(values : Array[Int], percent : Int) -> Int? {
  if values.length() == 0 || percent < 0 || percent > 100 {
    return None
  }
  let sorted = values.copy()
  sort_integers(sorted)
  let index = percent * (sorted.length() - 1) / 100
  Some(sorted[index])
}

///|
/// Return the median of a sample.
pub fn integer_median(values : Array[Int]) -> Int? {
  integer_percentile(values, 50)
}

///|
/// Return the mode, choosing the smallest value on ties.
pub fn integer_mode(values : Array[Int]) -> Int? {
  if values.length() == 0 {
    return None
  }
  let sorted = values.copy()
  sort_integers(sorted)
  let mut best = sorted[0]
  let mut best_count = 1
  let mut current = sorted[0]
  let mut current_count = 0
  for value in sorted {
    if value == current {
      current_count += 1
    } else {
      if current_count > best_count {
        best = current
        best_count = current_count
      }
      current = value
      current_count = 1
    }
  }
  if current_count > best_count {
    best = current
  }
  Some(best)
}

///|
/// Return a scaled covariance.
pub fn integer_covariance(
  left : Array[Int],
  right : Array[Int],
  scale : Int,
) -> Int? {
  if left.length() != right.length() || left.length() == 0 || scale <= 0 {
    return None
  }
  let left_mean = integer_mean(left)
  let right_mean = integer_mean(right)
  let mut total = 0
  for index in 0.. Int? {
  if left.length() != right.length() || left.length() == 0 {
    return None
  }
  let left_mean = integer_mean(left)
  let right_mean = integer_mean(right)
  let mut numerator = 0
  let mut left_total = 0
  let mut right_total = 0
  for index in 0.. IntegerHistogram {
  let counts : Array[Int] = []
  for _ in 0.. Bool {
  let index = (value - self.lower) / self.width
  if index < 0 || index >= self.counts.length() {
    return false
  }
  self.counts[index] += 1
  true
}

///|
/// Add all values and return the number accepted.
pub fn IntegerHistogram::add_all(
  self : IntegerHistogram,
  values : Array[Int],
) -> Int {
  let mut result = 0
  for value in values {
    if self.add(value) {
      result += 1
    }
  }
  result
}

///|
/// Return bucket counts.
pub fn IntegerHistogram::counts(self : IntegerHistogram) -> Array[Int] {
  self.counts.copy()
}

///|
/// Return a bucket count.
pub fn IntegerHistogram::bucket(self : IntegerHistogram, index : Int) -> Int {
  if index < 0 || index >= self.counts.length() {
    0
  } else {
    self.counts[index]
  }
}

///|
/// Return total accepted values.
pub fn IntegerHistogram::total(self : IntegerHistogram) -> Int {
  integer_sum(self.counts)
}

///|
/// Return the bucket with the largest count.
pub fn IntegerHistogram::peak(self : IntegerHistogram) -> Int? {
  if self.counts.length() == 0 {
    return None
  }
  let mut result = 0
  for index in 1.. self.counts[result] {
      result = index
    }
  }
  Some(result)
}

///|
/// Return moving averages with a fixed window.
pub fn moving_average(values : Array[Int], window : Int) -> Array[Int] {
  let result : Array[Int] = []
  if window <= 0 {
    return result
  }
  for index in 0.. Array[Int] {
  let result : Array[Int] = []
  for index in 1.. Array[Int] {
  let result : Array[Int] = []
  if values.length() == 0 || steps <= 0 {
    return result
  }
  let delta = integer_mean(first_differences(values))
  let mut current = values[values.length() - 1]
  for _ in 0.. Array[Int] {
  let result : Array[Int] = []
  let summary = integer_summary(values)
  let margin = integer_stddev(values) *
    (if deviations < 1 { 1 } else { deviations })
  for value in values {
    if value < summary.mean - margin || value > summary.mean + margin {
      result.push(value)
    }
  }
  result
}

///|
/// A pair of samples for regression.
pub struct IntegerRegression {
  slope_scaled : Int
  intercept : Int
  error : Int
}

///|
/// Fit y = slope*x + intercept with slope scaled by 1,000.
pub fn integer_regression(x : Array[Int], y : Array[Int]) -> IntegerRegression? {
  if x.length() != y.length() || x.length() == 0 {
    return None
  }
  let x_mean = integer_mean(x)
  let y_mean = integer_mean(y)
  let mut numerator = 0
  let mut denominator = 0
  for index in 0.. Int {
  self.slope_scaled
}

///|
/// Read intercept.
pub fn IntegerRegression::intercept(self : IntegerRegression) -> Int {
  self.intercept
}

///|
/// Read squared error.
pub fn IntegerRegression::error(self : IntegerRegression) -> Int {
  self.error
}

///|
/// Return a benchmark speedup percentage.
pub fn speedup_percent(baseline : Int, candidate : Int) -> Int? {
  if baseline <= 0 {
    return None
  }
  Some((baseline - candidate) * 100 / baseline)
}

///|
/// Return whether a metric regressed beyond a tolerance percentage.
pub fn regressed(
  baseline : Int,
  candidate : Int,
  tolerance_percent : Int,
) -> Bool {
  if baseline <= 0 {
    return candidate > baseline
  }
  candidate > baseline + baseline * tolerance_percent / 100
}