///|
/// A case groups alerts and tracks analyst workflow state.
pub(all) struct Case {
  id : String
  subject_id : String
  alerts : Array[Alert]
  status : AlertStatus
  notes : Array[String]
}

///|
pub fn Case::open(id : String, subject_id : String) -> Case {
  { id, subject_id, alerts: [], status: Open, notes: [] }
}

///|
pub fn Case::add_alert(self : Case, alert : Alert) -> Case {
  let alerts : Array[Alert] = []
  for old in self.alerts {
    alerts.push(old)
  }
  alerts.push(alert)
  { ..self, alerts, }
}

///|
pub fn Case::note(self : Case, message : String) -> Case {
  let notes : Array[String] = []
  for old in self.notes {
    notes.push(old)
  }
  notes.push(message)
  { ..self, notes, }
}

///|
pub fn Case::transition(self : Case, status : AlertStatus) -> Case {
  { ..self, status, }
}

///|
pub fn Case::risk(self : Case) -> RiskScore {
  let scores = aggregate_scores(self.alerts)
  match highest_score(scores) {
    Some(score) => score
    None => RiskScore::empty(self.subject_id)
  }
}

///|
pub fn group_cases(alerts : Array[Alert]) -> Array[Case] {
  let cases : Array[Case] = []
  for alert in alerts {
    let mut found = false
    let mut index = 0
    for case in cases {
      if case.subject_id == alert.transaction_id {
        cases[index] = case.add_alert(alert)
        found = true
      }
      index += 1
    }
    if !found {
      cases.push(
        Case::open("case-" + alert.transaction_id, alert.transaction_id).add_alert(
          alert,
        ),
      )
    }
  }
  cases
}

///|
pub fn actionable_cases(cases : Array[Case]) -> Array[Case] {
  let result : Array[Case] = []
  for case in cases {
    let mut actionable = false
    for alert in case.alerts {
      if alert.is_actionable() {
        actionable = true
      }
    }
    if actionable {
      result.push(case)
    }
  }
  result
}