///|
pub fn blast_radius_for_users(
  plan : RolloutPlan,
  users : Array[UserProfile],
  minute : Int,
) -> BlastRadius {
  let exposed = exposed_users(plan, users, minute)
  let traffic = total_traffic(exposed)
  let all_traffic = total_traffic(users)
  let percent_bp = if users.length() == 0 {
    0
  } else {
    exposed.length() * 10000 / users.length()
  }
  let traffic_bp = if all_traffic == 0 {
    0
  } else {
    traffic * 10000 / all_traffic
  }
  let risk_score = blast_score(
    percent_bp,
    traffic_bp,
    count_regions(exposed),
    count_tiers(exposed),
  )
  {
    exposed_users: exposed.length(),
    exposed_traffic_units: traffic,
    region_count: count_regions(exposed),
    tier_count: count_tiers(exposed),
    percent_bp,
    risk_score,
  }
}

///|
pub fn total_traffic(users : Array[UserProfile]) -> Int {
  let mut total = 0
  for user in users {
    total += user.traffic_units
  }
  total
}

///|
fn count_regions(users : Array[UserProfile]) -> Int {
  let mut na = false
  let mut eu = false
  let mut apac = false
  let mut cn = false
  let mut latam = false
  let mut mea = false
  let mut other = false
  for user in users {
    match user.region {
      NA => na = true
      EU => eu = true
      APAC => apac = true
      CN => cn = true
      LATAM => latam = true
      MEA => mea = true
      OtherRegion => other = true
    }
  }
  bool_count([na, eu, apac, cn, latam, mea, other])
}

///|
fn count_tiers(users : Array[UserProfile]) -> Int {
  let mut free = false
  let mut pro = false
  let mut enterprise = false
  let mut staff = false
  let mut internal = false
  for user in users {
    match user.tier {
      Free => free = true
      Pro => pro = true
      Enterprise => enterprise = true
      Staff => staff = true
      Internal => internal = true
    }
  }
  bool_count([free, pro, enterprise, staff, internal])
}

///|
fn bool_count(values : Array[Bool]) -> Int {
  let mut total = 0
  for value in values {
    if value {
      total += 1
    }
  }
  total
}

///|
fn blast_score(
  user_bp : Int,
  traffic_bp : Int,
  region_count : Int,
  tier_count : Int,
) -> Int {
  let user_part = user_bp / 120
  let traffic_part = traffic_bp / 90
  let region_part = region_count * 6
  let tier_part = tier_count * 4
  clamp(user_part + traffic_part + region_part + tier_part, 0, 100)
}

///|
pub fn blast_radius_markdown(blast : BlastRadius) -> String {
  let out = StringBuilder()
  out.write_string("## Blast Radius\n\n")
  out.write_string("- Exposed users: " + blast.exposed_users.to_string() + "\n")
  out.write_string(
    "- Exposed traffic units: " + blast.exposed_traffic_units.to_string() + "\n",
  )
  out.write_string("- Regions: " + blast.region_count.to_string() + "\n")
  out.write_string("- Tiers: " + blast.tier_count.to_string() + "\n")
  out.write_string("- User share: " + percent_text(blast.percent_bp) + "\n")
  out.write_string("- Risk score: " + blast.risk_score.to_string() + "/100\n")
  out.to_string()
}