///|
pub(all) enum AlertChannel {
  Pager
  Ticketing
  Log
} derive(Eq, Debug)

///|
pub(all) struct AlertRoute {
  level : AlertLevel
  channel : AlertChannel
  destination : String
} derive(Eq, Debug)

///|
pub fn AlertRoute::new(
  level : AlertLevel,
  channel : AlertChannel,
  destination : String,
) -> AlertRoute {
  { level, channel, destination }
}

///|
pub fn AlertRoute::channel_name(self : AlertRoute) -> String {
  match self.channel {
    Pager => "pager"
    Ticketing => "ticketing"
    Log => "log"
  }
}

///|
pub(all) struct EscalationPolicy {
  name : String
  routes : Array[AlertRoute]
  default_route : AlertRoute
} derive(Eq, Debug)

///|
pub fn EscalationPolicy::new(
  name : String,
  routes : Array[AlertRoute],
) -> EscalationPolicy {
  let default_route = AlertRoute::new(Ok, Log, "default")
  { name, routes, default_route }
}

///|
fn alert_level_rank(level : AlertLevel) -> Int {
  match level {
    Ok => 0
    Ticket => 1
    Page => 2
  }
}

///|
pub fn EscalationPolicy::route(
  self : EscalationPolicy,
  decision : AlertDecision,
) -> AlertRoute {
  let mut selected = self.default_route
  let mut selected_rank = -1
  for route in self.routes {
    if route.level == decision.level &&
      alert_level_rank(route.level) > selected_rank {
      selected = route
      selected_rank = alert_level_rank(route.level)
    }
  }
  selected
}

///|
pub fn EscalationPolicy::route_for_level(
  self : EscalationPolicy,
  level : AlertLevel,
) -> AlertRoute {
  self.route({
    level,
    rule_name: "policy",
    burn_rate_x100: 0,
    reason: "policy_lookup",
  })
}

///|
pub fn EscalationPolicy::route_count(self : EscalationPolicy) -> Int {
  self.routes.length()
}

///|
pub fn EscalationPolicy::has_channel(
  self : EscalationPolicy,
  channel : AlertChannel,
) -> Bool {
  for route in self.routes {
    if route.channel == channel {
      return true
    }
  }
  false
}

///|
pub fn EscalationPolicy::to_json(self : EscalationPolicy) -> String {
  let result = StringBuilder()
  result.write_string("{\"name\":\"\{escape_json(self.name)}\",\"routes\":[")
  for i, route in self.routes {
    if i > 0 {
      result.write_string(",")
    }
    result.write_string(
      "{\"level\":\"\{route.level.name()}\",\"channel\":\"\{route.channel_name()}\",\"destination\":\"\{escape_json(route.destination)}\"}",
    )
  }
  result.write_string("]}")
  result.to_string()
}

///|
pub fn EscalationPolicy::routes_for(
  self : EscalationPolicy,
  level : AlertLevel,
) -> Array[AlertRoute] {
  let result = []
  for route in self.routes {
    if route.level == level {
      result.push(route)
    }
  }
  result
}