///|
/// Policy metadata makes a rule set auditable without coupling it to storage.
pub(all) struct Policy {
  id : String
  name : String
  version : String
  owner : String
  enabled : Bool
  rules : Array[Rule]
}

///|
pub fn Policy::new(
  id : String,
  name : String,
  version : String,
  owner : String,
) -> Policy {
  { id, name, version, owner, enabled: true, rules: [] }
}

///|
pub fn Policy::add_rule(self : Policy, rule : Rule) -> Policy {
  let rules : Array[Rule] = []
  for old in self.rules {
    rules.push(old)
  }
  rules.push(rule)
  { ..self, rules, }
}

///|
pub fn Policy::disable(self : Policy) -> Policy {
  { ..self, enabled: false }
}

///|
pub fn Policy::enable(self : Policy) -> Policy {
  { ..self, enabled: true }
}

///|
pub fn Policy::evaluate(
  self : Policy,
  transactions : Array[Transaction],
) -> Array[Alert] {
  if self.enabled {
    evaluate(self.rules, transactions)
  } else {
    []
  }
}

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

///|
pub fn merge_policies(policies : Array[Policy]) -> Policy {
  let merged = Policy::new(
    "merged", "Combined monitoring policy", "1", "runtime",
  )
  let mut result = merged
  for policy in policies {
    for rule in policy.rules {
      result = result.add_rule(rule)
    }
  }
  result
}

///|
pub fn enabled_policies(policies : Array[Policy]) -> Array[Policy] {
  let result : Array[Policy] = []
  for policy in policies {
    if policy.enabled {
      result.push(policy)
    }
  }
  result
}

///|
pub fn evaluate_policies(
  policies : Array[Policy],
  transactions : Array[Transaction],
) -> Array[Alert] {
  let alerts : Array[Alert] = []
  for policy in policies {
    alerts.append(policy.evaluate(transactions))
  }
  deduplicate_alerts(alerts)
}