///|
/// `Bayesian` implements a simplified Bayesian Online Change Point Detection using a Normal-Gamma conjugate prior.
pub struct Bayesian {
  hazard_rate : Double
  mut run_length_probs : Array[Double]
  // Sufficient statistics for each run length
  mut mu_t : Array[Double]
  mut kappa_t : Array[Double]
  mut alpha_t : Array[Double]
  mut beta_t : Array[Double]
  // Prior parameters
  mu0 : Double
  kappa0 : Double
  alpha0 : Double
  beta0 : Double
  max_run_length : Int
}

///|
/// Creates a new Bayesian Online Change Point Detector.
pub fn Bayesian::new(
  hazard_rate? : Double = 0.01,
  mu0? : Double = 0.0,
  kappa0? : Double = 1.0,
  alpha0? : Double = 1.0,
  beta0? : Double = 1.0,
  max_run_length? : Int = 100,
) -> Bayesian {
  {
    hazard_rate,
    run_length_probs: [1.0],
    mu_t: [mu0],
    kappa_t: [kappa0],
    alpha_t: [alpha0],
    beta_t: [beta0],
    mu0,
    kappa0,
    alpha0,
    beta0,
    max_run_length,
  }
}

///|
/// Student-T probability density function (simplified)
fn student_t_pdf(
  x : Double,
  mu : Double,
  variance : Double,
  _nu : Double,
) -> Double {
  // We use a simplified Gaussian approximation for speed since this is a demonstration
  let diff = x - mu
  let exp_val = @math.exp(-(diff * diff) / (2.0 * variance))
  exp_val / (2.0 * 3.14159265358979323846 * variance).sqrt()
}

///|
/// Updates the detector and returns the probability of a change point at the current step.
pub fn Bayesian::update(self : Bayesian, value : Double) -> Double {
  let len = self.run_length_probs.length()

  // 1. Evaluate predictive probabilities for each run length
  let pred_probs = Array::make(len, 0.0)
  for i in 0.. self.max_run_length {
    self.max_run_length
  } else {
    new_probs.length()
  }
  let truncated_probs = Array::make(truncated_len, 0.0)
  for i in 0.. DetectionResult {
  let probability = self.update(value)
  DetectionResult::new(
    probability > 0.5,
    probability,
    probability,
    DistributionShift,
    index,
    evidence=probability,
  )
}