///|
/// Return only diagnostics at or above the requested severity.
pub fn filter_severity(
  diagnostics : Array[Diagnostic],
  minimum : Severity,
) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in diagnostics {
    let keep = match (minimum, diagnostic.severity) {
      (Error, Error) => true
      (Warning, Error | Warning) => true
      (Info, Error | Warning | Info) => true
      _ => false
    }
    if keep {
      result.push(diagnostic)
    }
  }
  result
}

///|
/// Return diagnostics whose rule code is in the requested set.
pub fn filter_codes(
  diagnostics : Array[Diagnostic],
  codes : Array[String],
) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in diagnostics {
    if codes.contains(diagnostic.code) {
      result.push(diagnostic)
    }
  }
  result
}

///|
/// Return one copy of each structurally equal diagnostic.
pub fn deduplicate(diagnostics : Array[Diagnostic]) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in diagnostics {
    if !result.contains(diagnostic) {
      result.push(diagnostic)
    }
  }
  result
}

///|
/// Count diagnostics by severity in a stable tuple.
pub fn severity_counts(diagnostics : Array[Diagnostic]) -> (Int, Int, Int) {
  let mut errors = 0
  let mut warnings = 0
  let mut infos = 0
  for diagnostic in diagnostics {
    match diagnostic.severity {
      Error => errors += 1
      Warning => warnings += 1
      Info => infos += 1
    }
  }
  (errors, warnings, infos)
}

///|
/// Add a note to every diagnostic in a batch.
pub fn annotate(
  diagnostics : Array[Diagnostic],
  note : String,
) -> Array[Diagnostic] {
  let result : Array[Diagnostic] = []
  for diagnostic in diagnostics {
    result.push(diagnostic.with_note(note))
  }
  result
}