///|
/// `DetectorType` represents the type of change point detector to use.
pub(all) enum DetectorType {
  CusumDetector(Cusum)
  PageHinkleyDetector(PageHinkley)
  BayesianDetector(Bayesian)
}

///|
/// `Detector` wraps a specific algorithm and supports multi-metric alert suppression.
pub struct Detector {
  detector : DetectorType
  mut suppression_count : Int
  suppression_limit : Int
}

///|
/// Creates a new multi-metric detector wrapper.
pub fn Detector::new(
  detector : DetectorType,
  suppression_limit? : Int = 3,
) -> Detector {
  { detector, suppression_count: 0, suppression_limit }
}

///|
/// Updates the detector and handles alert suppression. Returns true if an unsuppressed alert is triggered.
pub fn Detector::update(self : Detector, value : Double) -> Bool {
  let detected = match self.detector {
    CusumDetector(c) => c.update(value)
    PageHinkleyDetector(p) => p.update(value)
    BayesianDetector(b) => b.update(value) > 0.5
  }

  if detected {
    if self.suppression_count < self.suppression_limit {
      self.suppression_count += 1
      return false // Suppressed
    } else {
      self.suppression_count = 0
      return true // Alert
    }
  } else if self.suppression_count > 0 {
    self.suppression_count -= 1
  }
  return false
}

///|
/// Rich result form of the detector wrapper. Suppression is applied to the change flag only.
pub fn Detector::update_result(
  self : Detector,
  value : Double,
  index? : Int = 0,
) -> DetectionResult {
  let result = match self.detector {
    CusumDetector(c) => c.update_result(value, index~)
    PageHinkleyDetector(p) => p.update_result(value, index~)
    BayesianDetector(b) => b.update_result(value, index~)
  }
  let emitted = if result.changed {
    if self.suppression_count < self.suppression_limit {
      self.suppression_count += 1
      false
    } else {
      self.suppression_count = 0
      true
    }
  } else {
    if self.suppression_count > 0 {
      self.suppression_count -= 1
    }
    false
  }
  {
    changed: emitted,
    score: result.score,
    confidence: result.confidence,
    direction: result.direction,
    index: result.index,
    evidence: result.evidence,
  }
}