///|
pub(all) struct WindowPolicy {
  name : String
  minutes : Int
  required : Bool
} derive(Eq, Debug)

///|
pub fn WindowPolicy::new(
  name : String,
  minutes : Int,
  required : Bool,
) -> WindowPolicy {
  { name, minutes: if minutes > 0 { minutes } else { 1 }, required }
}

///|
pub fn WindowPolicy::duration_label(self : WindowPolicy) -> String {
  if self.minutes % 1440 == 0 {
    "\{self.minutes / 1440}d"
  } else if self.minutes % 60 == 0 {
    "\{self.minutes / 60}h"
  } else {
    "\{self.minutes}m"
  }
}

///|
pub(all) struct SloConfig {
  target : SloTarget
  windows : Array[WindowPolicy]
  rules : Array[BurnRule]
} derive(Eq, Debug)

///|
pub fn SloConfig::new(
  target : SloTarget,
  windows : Array[WindowPolicy],
  rules : Array[BurnRule],
) -> SloConfig {
  { target, windows, rules }
}

///|
pub fn SloConfig::window_count(self : SloConfig) -> Int {
  self.windows.length()
}

///|
pub fn SloConfig::rule_count(self : SloConfig) -> Int {
  self.rules.length()
}

///|
pub fn SloConfig::has_window(self : SloConfig, name : String) -> Bool {
  for window in self.windows {
    if window.name == name {
      return true
    }
  }
  false
}

///|
pub fn SloConfig::has_rule(self : SloConfig, name : String) -> Bool {
  for rule in self.rules {
    if rule.name == name {
      return true
    }
  }
  false
}

///|
pub fn SloConfig::to_json(self : SloConfig) -> String {
  let windows = StringBuilder()
  windows.write_string("[")
  for i, window in self.windows {
    if i > 0 {
      windows.write_string(",")
    }
    windows.write_string(
      "{\"name\":\"\{escape_json(window.name)}\",\"minutes\":\{window.minutes},\"required\":\{window.required}}",
    )
  }
  windows.write_string("]")
  let rules = StringBuilder()
  rules.write_string("[")
  for i, rule in self.rules {
    if i > 0 {
      rules.write_string(",")
    }
    rules.write_string(
      "{\"name\":\"\{escape_json(rule.name)}\",\"level\":\"\{rule.level.name()}\",\"threshold_x100\":\{rule.threshold_x100}}",
    )
  }
  rules.write_string("]")
  "{\"target\":\"\{escape_json(self.target.name)}\",\"target_bp\":\{self.target.target_bp},\"windows\":\{windows.to_string()},\"rules\":\{rules.to_string()}}"
}

///|
pub fn default_slo_config(target : SloTarget) -> SloConfig {
  SloConfig::new(
    target,
    [
      WindowPolicy::new("5m", 5, true),
      WindowPolicy::new("1h", 60, true),
      WindowPolicy::new("6h", 360, false),
      WindowPolicy::new("24h", 1440, false),
    ],
    standard_burn_rules(),
  )
}

///|
pub fn SloConfig::required_windows(self : SloConfig) -> Array[WindowPolicy] {
  let result = []
  for window in self.windows {
    if window.required {
      result.push(window)
    }
  }
  result
}