///|
/// An IPv6 route whose origin-validation state changes between snapshots.
pub(all) struct Ipv6RouteImpact {
  previous : Ipv6ValidationDecision
  current : Ipv6ValidationDecision
}

///|
pub fn Ipv6RouteImpact::summary(self : Ipv6RouteImpact) -> String {
  let route = self.current.route
  "AS\{route.origin_asn()} \{route.prefix().to_string()}: \{validity_label(self.previous.validity)} -> \{validity_label(self.current.validity)}"
}

///|
fn write_ipv6_decision_evidence(
  buffer : StringBuilder,
  label : String,
  decision : Ipv6ValidationDecision,
) -> Unit {
  buffer.write_string("  \{label} (\{validity_label(decision.validity)}):")
  if decision.matches.is_empty() {
    buffer.write_string("\n    no covering VRP")
  } else {
    for evidence in decision.matches {
      let vrp = evidence.vrp
      buffer.write_string(
        "\n    AS\{vrp.asn()} \{vrp.prefix().to_string()} maxLength \{vrp.max_length()}: \{human_relation_label(evidence.relation)}",
      )
    }
  }
}

///|
pub fn Ipv6RouteImpact::explanation(self : Ipv6RouteImpact) -> String {
  let buffer = StringBuilder()
  buffer.write_string(self.summary())
  buffer.write_char('\n')
  write_ipv6_decision_evidence(buffer, "before", self.previous)
  buffer.write_char('\n')
  write_ipv6_decision_evidence(buffer, "after", self.current)
  buffer.to_string()
}

///|
/// IPv6 route-state changes caused by replacing one VRP snapshot.
pub(all) struct Ipv6SnapshotImpact {
  changed : Array[Ipv6RouteImpact]
  unchanged : Int
}

///|
pub fn Ipv6SnapshotImpact::is_empty(self : Ipv6SnapshotImpact) -> Bool {
  self.changed.is_empty()
}

///|
pub fn Ipv6SnapshotImpact::summary(self : Ipv6SnapshotImpact) -> String {
  "\{self.changed.length()} changed (\{self.unchanged} unchanged)"
}

///|
/// Evaluate IPv6 route decisions against old and new VRP snapshots.
///
/// Only validity transitions appear in changed. Changes to evidence that
/// preserve the validity state are counted as unchanged.
pub fn assess_ipv6_snapshot_impact(
  routes : Array[Ipv6RouteAnnouncement],
  previous_vrps : Array[Ipv6Vrp],
  current_vrps : Array[Ipv6Vrp],
) -> Ipv6SnapshotImpact {
  let previous_index = Ipv6VrpIndex::new(previous_vrps)
  let current_index = Ipv6VrpIndex::new(current_vrps)
  let changed : Array[Ipv6RouteImpact] = []
  let mut unchanged = 0
  for route in routes {
    let previous = previous_index.validate(route)
    let current = current_index.validate(route)
    if previous.validity == current.validity {
      unchanged = unchanged + 1
    } else {
      changed.push({ previous, current, })
    }
  }
  { changed, unchanged, }
}