///|
fn format_double(value : Double, decimals : Int) -> String {
  if value.is_nan() {
    return "NaN"
  }
  if value.is_inf() {
    return "Inf"
  }
  if value < 0.0 {
    return "-" + format_double(-value, decimals)
  }
  let mut factor = 1.0
  let mut index = 0
  while index < decimals {
    factor = factor * 10.0
    index = index + 1
  }
  let rounded = (value * factor + 0.5).floor().to_int()
  let digits = rounded.to_string()
  if decimals == 0 {
    return digits
  }
  if digits.length() <= decimals {
    let mut prefix = "0."
    let mut padding = 0
    while padding < decimals - digits.length() {
      prefix = prefix + "0"
      padding = padding + 1
    }
    return prefix + digits
  }
  let split = digits.length() - decimals
  digits.sub(start=0, end=split).to_owned() +
  "." +
  digits.sub(start=split, end=digits.length()).to_owned()
}

///|
fn status_name(status : @lib.ParticleStatus) -> String {
  match status {
    @lib.ParticleStatus::Transmitted => "transmitted"
    @lib.ParticleStatus::Absorbed => "absorbed"
    @lib.ParticleStatus::Backscattered => "backscattered"
    @lib.ParticleStatus::Active => "active"
  }
}

///|
fn main {
  println("MoonBit Radiation Transport and Shielding")
  println("===========================================")

  let energy = 1.25
  let layers = @lib.lead_concrete_wall(5.0, 20.0)
  let stack = @lib.LayerStack::from_layers(layers)
  let narrow_beam = stack.analytic_transmission(energy)
  let buildup = stack.analytic_buildup_transmission(energy)
  let total_thickness = stack.total_thickness

  println("Scenario: 5 cm lead + 20 cm concrete slab")
  println("Reference energy: " + format_double(energy, 2) + " MeV")
  println(
    "Total thickness: " +
    format_double(total_thickness, 1) +
    " cm, " +
    "areal density: " +
    format_double(@lib.areal_density(layers), 2) +
    " g/cm2",
  )
  println(
    "Analytical narrow-beam transmission: " +
    format_double(narrow_beam * 100.0, 5) +
    "%",
  )
  println(
    "Analytical buildup transmission:      " +
    format_double(buildup * 100.0, 5) +
    "%",
  )

  let options = @lib.demo_transport_options(5000)
  let result = @lib.run_transport(options)
  let quality = @lib.quality_metrics(result, layers, 1.2525)
  println("")
  println("Monte Carlo run: " + result.histories.to_string() + " histories")
  println(
    "Transmission: " +
    format_double(result.transmission_fraction * 100.0, 4) +
    "% +/- " +
    format_double(result.transmission_sem * 100.0, 4) +
    "% SEM",
  )
  println(
    "Terminal status: transmitted=" +
    result.transmitted.to_string() +
    ", absorbed=" +
    result.absorbed.to_string() +
    ", backscattered=" +
    result.backscattered.to_string() +
    ", cutoff=" +
    result.cutoff.to_string(),
  )
  println(
    "Mean deposited energy: " +
    format_double(result.mean_deposited_energy, 6) +
    " MeV/history",
  )
  println(
    "Quality gates: probability=" +
    quality.probability_conservation.to_string() +
    ", energy=" +
    quality.energy_conservation.to_string() +
    ", geometry=" +
    quality.geometry_valid.to_string() +
    ", errors=" +
    quality.errors.to_string(),
  )

  println("")
  println("Recorded history sample:")
  let mut history_index = 0
  while history_index < result.recorded_histories.length() {
    let history = result.recorded_histories[history_index]
    println(
      "  #" +
      history.id.to_string() +
      " " +
      status_name(history.status) +
      ", path=" +
      format_double(history.path_length, 3) +
      " cm, events=" +
      history.events.length().to_string(),
    )
    history_index = history_index + 1
  }

  println("")
  println("Run the full verification suite with:")
  println("  moon check --target all --deny-warn")
  println("  moon test --target native --deny-warn")
  println("===========================================")
}