///|
/// Runtime diagnostics for reproducible local and CI performance checks.
/// Callers provide measured wall-clock values; this module summarizes them
/// without embedding machine-specific claims in the library.
pub(all) struct RuntimeSample {
  case_name : String
  target : String
  repetitions : Int
  elapsed_ms : Double
  input_size : Int
  output_size : Int
  accepted : Bool
} derive(FromJson, ToJson, Debug, Eq)

///|
pub(all) struct RuntimeAggregate {
  case_name : String
  target : String
  sample_count : Int
  mean_ms : Double
  median_ms : Double
  minimum_ms : Double
  maximum_ms : Double
  standard_deviation_ms : Double
  throughput_per_second : Double
  stable : Bool
} derive(FromJson, ToJson, Debug, Eq)

///|
pub(all) struct RuntimeBudget {
  case_name : String
  target : String
  maximum_mean_ms : Double
  maximum_p95_ms : Double
  minimum_throughput : Double
  minimum_stability : Double
} derive(FromJson, ToJson, Debug, Eq)

///|
pub(all) struct RuntimeCheck {
  aggregate : RuntimeAggregate
  budget : RuntimeBudget
  passed : Bool
  reasons : Array[String]
} derive(FromJson, ToJson, Debug, Eq)

///|
pub(all) struct RuntimeReport {
  samples : Array[RuntimeSample]
  aggregates : Array[RuntimeAggregate]
  checks : Array[RuntimeCheck]
  passed : Bool
  feature_vector : Array[Double]
} derive(FromJson, ToJson, Debug, Eq)

///|
fn runtime_bound(value : Double, low : Double, high : Double) -> Double {
  if value.is_nan() || value.is_inf() {
    low
  } else {
    value.clamp(min=low, max=high)
  }
}

///|
pub fn make_runtime_sample(
  case_name : String,
  target : String,
  repetitions : Int,
  elapsed_ms : Double,
  input_size : Int,
  output_size : Int,
  accepted : Bool,
) -> RuntimeSample {
  {
    case_name,
    target,
    repetitions: repetitions.max(1),
    elapsed_ms: runtime_bound(elapsed_ms, 0.0, 86400000.0),
    input_size: input_size.max(0),
    output_size: output_size.max(0),
    accepted,
  }
}

///|
fn runtime_min(values : Array[Double]) -> Double {
  if values.length() == 0 {
    0.0
  } else {
    let mut result = values[0]
    for value in values {
      if value < result {
        result = value
      }
    }
    result
  }
}

///|
fn runtime_max(values : Array[Double]) -> Double {
  if values.length() == 0 {
    0.0
  } else {
    let mut result = values[0]
    for value in values {
      if value > result {
        result = value
      }
    }
    result
  }
}

///|
fn runtime_p95(values : Array[Double]) -> Double {
  quantile_value(values, 0.95)
}

///|
pub fn aggregate_runtime_samples(
  samples : Array[RuntimeSample],
  case_name : String,
  target : String,
) -> RuntimeAggregate {
  let selected = samples.filter(sample => {
    sample.case_name == case_name && sample.target == target
  })
  let elapsed = selected.map(sample => sample.elapsed_ms)
  let mean = mean_value(elapsed)
  let median = median_value(elapsed)
  let minimum = runtime_min(elapsed)
  let maximum = runtime_max(elapsed)
  let input = mean_value(selected.map(sample => sample.input_size.to_double()))
  let throughput = if mean <= 0.000001 { 0.0 } else { input / (mean / 1000.0) }
  let relative_sd = if mean <= 0.000001 {
    1.0
  } else {
    standard_deviation(elapsed) / mean
  }
  {
    case_name,
    target,
    sample_count: selected.length(),
    mean_ms: mean,
    median_ms: median,
    minimum_ms: minimum,
    maximum_ms: maximum,
    standard_deviation_ms: standard_deviation(elapsed),
    throughput_per_second: throughput,
    stable: selected.length() > 1 && relative_sd <= 0.25,
  }
}

///|
pub fn runtime_budget(
  case_name : String,
  target : String,
  maximum_mean_ms : Double,
  maximum_p95_ms : Double,
  minimum_throughput : Double,
  minimum_stability : Double,
) -> RuntimeBudget {
  {
    case_name,
    target,
    maximum_mean_ms: maximum_mean_ms.max(0.0),
    maximum_p95_ms: maximum_p95_ms.max(0.0),
    minimum_throughput: minimum_throughput.max(0.0),
    minimum_stability: minimum_stability.clamp(min=0.0, max=1.0),
  }
}

///|
pub fn check_runtime_budget(
  aggregate : RuntimeAggregate,
  budget : RuntimeBudget,
) -> RuntimeCheck {
  let reasons = []
  let stability = if aggregate.stable { 1.0 } else { 0.0 }
  if aggregate.mean_ms > budget.maximum_mean_ms {
    reasons.push("mean latency exceeds the budget")
  }
  if runtime_p95([
      aggregate.minimum_ms,
      aggregate.median_ms,
      aggregate.maximum_ms,
    ]) >
    budget.maximum_p95_ms {
    reasons.push("p95 proxy exceeds the budget")
  }
  if aggregate.throughput_per_second < budget.minimum_throughput {
    reasons.push("throughput is below the budget")
  }
  if stability < budget.minimum_stability {
    reasons.push("sample variation is above the stability budget")
  }
  { aggregate, budget, passed: reasons.length() == 0, reasons }
}

///|
fn runtime_unique_cases(samples : Array[RuntimeSample]) -> Array[String] {
  let result = []
  for sample in samples {
    if !result.any(name => name == sample.case_name) {
      result.push(sample.case_name)
    }
  }
  result
}

///|
fn runtime_unique_targets(samples : Array[RuntimeSample]) -> Array[String] {
  let result = []
  for sample in samples {
    if !result.any(name => name == sample.target) {
      result.push(sample.target)
    }
  }
  result
}

///|
fn runtime_find_aggregate(
  aggregates : Array[RuntimeAggregate],
  case_name : String,
  target : String,
) -> RuntimeAggregate? {
  for aggregate in aggregates {
    if aggregate.case_name == case_name && aggregate.target == target {
      return Some(aggregate)
    }
  }
  None
}

///|
pub fn build_runtime_report(
  samples : Array[RuntimeSample],
  budgets : Array[RuntimeBudget],
) -> RuntimeReport {
  let aggregates = []
  let cases = runtime_unique_cases(samples)
  let targets = runtime_unique_targets(samples)
  for case_name in cases {
    for target in targets {
      if samples.any(sample => {
          sample.case_name == case_name && sample.target == target
        }) {
        aggregates.push(aggregate_runtime_samples(samples, case_name, target))
      }
    }
  }
  let checks = []
  for budget in budgets {
    let aggregate = runtime_find_aggregate(
      aggregates,
      budget.case_name,
      budget.target,
    )
    match aggregate {
      Some(value) => checks.push(check_runtime_budget(value, budget))
      None =>
        checks.push({
          aggregate: aggregate_runtime_samples(
            samples,
            budget.case_name,
            budget.target,
          ),
          budget,
          passed: false,
          reasons: ["no matching runtime sample"],
        })
    }
  }
  let features = []
  for aggregate in aggregates {
    features.push(aggregate.mean_ms)
    features.push(aggregate.median_ms)
    features.push(aggregate.throughput_per_second)
    features.push(if aggregate.stable { 1.0 } else { 0.0 })
  }
  {
    samples,
    aggregates,
    checks,
    passed: checks.all(check => check.passed),
    feature_vector: features,
  }
}

///|
pub fn runtime_report_is_usable(report : RuntimeReport) -> Bool {
  report.samples.length() > 0 &&
  report.aggregates.length() > 0 &&
  report.checks.length() > 0
}

///|
pub fn runtime_report_csv(report : RuntimeReport) -> String {
  let grid = [
    [
      "case_name", "target", "sample_count", "mean_ms", "median_ms", "minimum_ms",
      "maximum_ms", "standard_deviation_ms", "throughput_per_second", "stable",
    ],
  ]
  for aggregate in report.aggregates {
    grid.push([
      aggregate.case_name,
      aggregate.target,
      aggregate.sample_count.to_string(),
      aggregate.mean_ms.to_string(),
      aggregate.median_ms.to_string(),
      aggregate.minimum_ms.to_string(),
      aggregate.maximum_ms.to_string(),
      aggregate.standard_deviation_ms.to_string(),
      aggregate.throughput_per_second.to_string(),
      aggregate.stable.to_string(),
    ])
  }
  to_csv(grid)
}

///|
pub fn runtime_check_csv(report : RuntimeReport) -> String {
  let grid = [["case_name", "target", "passed", "reason_count", "reasons"]]
  for check in report.checks {
    grid.push([
      check.budget.case_name,
      check.budget.target,
      check.passed.to_string(),
      check.reasons.length().to_string(),
      check.reasons.join("|"),
    ])
  }
  to_csv(grid)
}

///|
pub fn runtime_report_summary(report : RuntimeReport) -> String {
  let failed = report.checks.filter(check => !check.passed).length()
  "\{report.aggregates.length().to_string()} aggregate cases, \{failed.to_string()} failed budgets"
}

///|
pub fn runtime_regression_ratio(
  current : RuntimeAggregate,
  previous : RuntimeAggregate,
) -> Double {
  if previous.mean_ms <= 0.000001 {
    0.0
  } else {
    current.mean_ms / previous.mean_ms - 1.0
  }
}

///|
pub fn runtime_throughput_ratio(
  current : RuntimeAggregate,
  previous : RuntimeAggregate,
) -> Double {
  if previous.throughput_per_second <= 0.000001 {
    0.0
  } else {
    current.throughput_per_second / previous.throughput_per_second - 1.0
  }
}

///|
pub fn runtime_has_regression(
  current : RuntimeAggregate,
  previous : RuntimeAggregate,
  threshold : Double,
) -> Bool {
  runtime_regression_ratio(current, previous) > threshold.max(0.0)
}

///|
pub fn runtime_aggregate_feature_vector(
  aggregate : RuntimeAggregate,
) -> Array[Double] {
  [
    aggregate.sample_count.to_double(),
    aggregate.mean_ms,
    aggregate.median_ms,
    aggregate.minimum_ms,
    aggregate.maximum_ms,
    aggregate.standard_deviation_ms,
    aggregate.throughput_per_second,
    if aggregate.stable {
      1.0
    } else {
      0.0
    },
  ]
}

///|
pub fn runtime_samples_for(
  samples : Array[RuntimeSample],
  case_name : String,
  target : String,
) -> Array[RuntimeSample] {
  samples.filter(sample => {
    sample.case_name == case_name && sample.target == target
  })
}

///|
pub fn runtime_acceptance_ratio(samples : Array[RuntimeSample]) -> Double {
  if samples.length() == 0 {
    0.0
  } else {
    samples.filter(sample => sample.accepted).length().to_double() /
    samples.length().to_double()
  }
}

///|
pub fn runtime_input_throughput(sample : RuntimeSample) -> Double {
  if sample.elapsed_ms <= 0.000001 {
    0.0
  } else {
    sample.input_size.to_double() / (sample.elapsed_ms / 1000.0)
  }
}

///|
pub fn runtime_output_throughput(sample : RuntimeSample) -> Double {
  if sample.elapsed_ms <= 0.000001 {
    0.0
  } else {
    sample.output_size.to_double() / (sample.elapsed_ms / 1000.0)
  }
}

///|
pub fn runtime_report_feature_vector(report : RuntimeReport) -> Array[Double] {
  let result = []
  for value in report.feature_vector {
    result.push(value)
  }
  result.push(report.samples.length().to_double())
  result.push(report.checks.filter(check => check.passed).length().to_double())
  result
}