///|
/// Rate cumulative usage according to the plan mode; never rounds individual lines.
///
/// ```mbt check
/// test {
///   let plan = @jieheng.compile_plan(
///     id="api",
///     version="v1",
///     metric="requests",
///     unit="request",
///     currency="USD",
///     tiers=[
///       { up_to: Some("1000"), unit_price: "0", },
///       { up_to: None, unit_price: "0.001", },
///     ],
///   )
///   let result = @jieheng.rate(plan, {
///     customer: "acme",
///     metric: "requests",
///     period: "2026-09",
///     quantity: "1001",
///   })
///   inspect(result.total, content="0.001")
/// }
/// ```
pub fn rate(plan : Plan, usage : Usage) -> Calculation raise PricingError {
  let quantity = validate_usage(plan, usage)
  let lines = []
  let mut lower = 0N
  let mut total = 0N
  if plan.mode == Volume {
    if quantity > 0N {
      for index, tier in plan.tiers {
        let selected = match tier.up_to {
          Some(bound) => quantity <= bound
          None => true
        }
        if selected {
          total = quantity * tier.price
          lines.push({
            tier: index,
            from_exclusive: "0",
            to_inclusive: quantity.to_string(),
            quantity: quantity.to_string(),
            unit_price: format_atoms(tier.price),
            subtotal: format_atoms(total),
          })
          break
        }
      }
    }
    return {
      plan_id: plan.id,
      plan_version: plan.version,
      currency: plan.currency,
      unit: plan.unit,
      usage,
      lines,
      total: format_atoms(total),
    }
  }
  for index, tier in plan.tiers {
    if lower >= quantity {
      break
    }
    let upper = match tier.up_to {
      Some(bound) => if bound < quantity { bound } else { quantity }
      None => quantity
    }
    let count = upper - lower
    let subtotal = count * tier.price
    lines.push({
      tier: index,
      from_exclusive: lower.to_string(),
      to_inclusive: upper.to_string(),
      quantity: count.to_string(),
      unit_price: format_atoms(tier.price),
      subtotal: format_atoms(subtotal),
    })
    total += subtotal
    lower = upper
  }
  {
    plan_id: plan.id,
    plan_version: plan.version,
    currency: plan.currency,
    unit: plan.unit,
    usage,
    lines,
    total: format_atoms(total),
  }
}