///|
pub(all) enum QualityFlag {
  Good
  Missing
  Suspect
  Bad
} derive(Debug, Eq)

///|
pub(all) enum Severity {
  Info
  Warning
  Error
} derive(Debug, Eq)

///|
pub(all) enum RuleKind {
  Range
  Missing
  Spike
  Duplicate
  Interval
  SpatialJump
  ClimateAnomaly
  Multivariate
} derive(Debug, Eq)

///|
pub(all) struct Observation {
  id : String
  timestamp : Int
  latitude : Double
  longitude : Double
  variable : String
  value : Double?
  unit : String
  platform : String
} derive(Debug)

///|
pub fn Observation::new(
  id~ : String,
  timestamp~ : Int,
  latitude~ : Double,
  longitude~ : Double,
  variable~ : String,
  value~ : Double?,
  unit~ : String,
  platform~ : String,
) -> Observation {
  { id, timestamp, latitude, longitude, variable, value, unit, platform }
}

///|
pub(all) struct Provenance {
  source : String
  dataset : String
  observed_at : Int
  processor : String
  version : String
} derive(Debug)

///|
pub(all) struct Finding {
  observation_id : String
  rule : RuleKind
  flag : QualityFlag
  severity : Severity
  reason : String
  original_value : Double?
  processed_at : Int
  provenance : Provenance
} derive(Debug)

///|
pub(all) struct RuleConfig {
  range_min : Double?
  range_max : Double?
  max_delta : Double?
  max_interval : Int?
  max_speed : Double?
  climate_min : Double?
  climate_max : Double?
  duplicate_window : Int
  processing_time : Int
} derive(Debug)

///|
pub fn RuleConfig::default() -> RuleConfig {
  {
    range_min: None,
    range_max: None,
    max_delta: None,
    max_interval: None,
    max_speed: None,
    climate_min: None,
    climate_max: None,
    duplicate_window: 0,
    processing_time: 0,
  }
}

///|
pub(all) struct QcSummary {
  total : Int
  good : Int
  missing : Int
  suspect : Int
  bad : Int
  findings : Array[Finding]
} derive(Debug)