///|
/// Long-run outcomes for attempted and admitted arrivals. Waiting time is
/// averaged over all admitted customers, including those who abandon.
pub(all) struct FiniteOutcomes {
  accepted_fraction : Double
  served_fraction : Double
  abandoned_fraction : Double
  served_given_admission : Double
  abandoned_given_admission : Double
  mean_admitted_wait : Double
  relative_rate_residual : Double
} derive(Debug, ToJson)

///|
pub fn FiniteQueue::outcomes(
  self : FiniteQueue,
) -> FiniteOutcomes raise QueueError {
  let m = self.analyze()
  if self.arrival == 0.0 {
    return {
      accepted_fraction: 1.0,
      served_fraction: 1.0,
      abandoned_fraction: 0.0,
      served_given_admission: 1.0,
      abandoned_given_admission: 0.0,
      mean_admitted_wait: 0.0,
      relative_rate_residual: 0.0,
    }
  }
  let residual = (m.admitted_rate - m.service_rate - m.abandon_rate).abs() /
    m.admitted_rate
  if residual > 1.0e-8 {
    raise Numerical("finite departure flow is inconsistent")
  }
  let accepted = m.admitted_rate / self.arrival
  let served = m.service_rate / m.admitted_rate
  let abandoned = m.abandon_rate / m.admitted_rate
  {
    accepted_fraction: accepted,
    served_fraction: accepted * served,
    abandoned_fraction: accepted * abandoned,
    served_given_admission: served,
    abandoned_given_admission: abandoned,
    mean_admitted_wait: checked_ratio(
      m.mean_queue,
      m.admitted_rate,
      "admitted wait",
    ),
    relative_rate_residual: residual,
  }
}

///|
pub extend FiniteOutcomes with Debug::{to_repr}

///|
pub extend FiniteOutcomes with ToJson::{to_json}