///|
/// 18-vented-electronics-enclosure
///
/// A working example that generates a STEP model for: A vented box generator:
/// walls, lid, screw bosses, and parametric vent patterns.
///
/// Usage (stdout):
///   moon run --target native examples/18-vented-electronics-enclosure -- --width 80 --length 120 --height 40 > enclosure.step
async fn main {
  let base_args_spec = {
    "width": @cli.opt_double(80.0, help="Outer width of the box (mm)", min=20.0),
    "length": @cli.opt_double(
      120.0,
      help="Outer length of the box (mm)",
      min=20.0,
    ),
    "height": @cli.opt_double(
      40.0,
      help="Total height of the box body (mm)",
      min=5.0,
    ),
    "wallThickness": @cli.opt_double(
      2.5,
      help="Thickness of the walls (mm)",
      min=1.0,
    ),
    "filletRadius": @cli.opt_double(
      5.0,
      help="Corner fillet radius (mm)",
      min=0.0,
    ),
    "bossOD": @cli.opt_double(
      8.0,
      help="Screw boss outer diameter (mm)",
      min=1.0,
    ),
    "bossID": @cli.opt_double(
      3.2,
      help="Screw boss inner (hole) diameter (mm)",
      min=0.5,
    ),
    "lidThickness": @cli.opt_double(
      3.0,
      help="Thickness of the lid (mm)",
      min=1.0,
    ),
    "ventWidth": @cli.opt_double(2.0, help="Width of vent slots (mm)", min=0.5),
    "ventSpacing": @cli.opt_double(
      4.0,
      help="Spacing between vent slots (mm)",
      min=1.0,
    ),
  }
  let args_spec = @cli.with_translate(@common.with_output_args(base_args_spec))
  guard @cli.parse(
      args_spec,
      prog="18-vented-electronics-enclosure",
      description="Generate a vented electronics enclosure STEP model.",
    )
    is Some(args) else {
    return
  }
  let width = args.double("width")
  let length = args.double("length")
  let height = args.double("height")
  let wall_thickness = args.double("wallThickness")
  let fillet_radius = args.double("filletRadius")
  let boss_od = args.double("bossOD")
  let boss_id = args.double("bossID")
  let lid_thickness = args.double("lidThickness")
  let vent_width = args.double("ventWidth")
  let vent_spacing = args.double("ventSpacing")
  let output = @common.output_paths(args)
  let (tx, ty, tz) = match args.translate_xyz() {
    Some(v) => v
    None => {
      @cli.eprintln("error: invalid translation")
      return
    }
  }
  let nodes = vented_enclosure(
    width,
    length,
    height,
    wall_thickness,
    fillet_radius,
    boss_od,
    boss_id,
    lid_thickness,
    vent_slot_width=vent_width,
    vent_slot_spacing=vent_spacing,
  )
  let mut design = @cad.Design::new(
    name="vented-enclosure",
    documentation=args.documentation(),
  )
  for node in nodes {
    design = design.add(
      node.translate(x=tx - width / 2.0, y=ty - length / 2.0, z=tz),
    )
  }
  @common.write_output(design, output)
}

///|
fn vented_enclosure(
  width : Double,
  length : Double,
  height : Double,
  wall_thickness : Double,
  fillet_radius : Double,
  boss_diameter : Double,
  boss_hole_diameter : Double,
  lid_thickness : Double,
  vent_slot_width~ : Double = 2.0,
  vent_slot_spacing~ : Double = 4.0,
) -> Array[@cad.SceneNode] {
  let outer = @cad.Profile2D::rounded_rect(width, length, fillet_radius)
  let inner_r = if fillet_radius > wall_thickness {
    fillet_radius - wall_thickness
  } else {
    0.0
  }
  let inner = @cad.Profile2D::rounded_rect(
      width - 2.0 * wall_thickness,
      length - 2.0 * wall_thickness,
      inner_r,
    )
    .map(fn(p) { (p.0 + wall_thickness, p.1 + wall_thickness) })
    .rev()

  // 1. Body Bottom
  let bottom = @cad.ExtrudedProfile::new(outer, wall_thickness)
    .with_name("body-bottom")
    .with_color(@cad.Rgb::blue())

  // 2. Body Walls
  let walls = @cad.ExtrudedProfile::new(outer, height - wall_thickness, holes=[
      inner,
    ])
    .with_name("body-walls")
    .with_color(@cad.Rgb::blue())
    .translate(z=wall_thickness)
  let nodes = [bottom, walls]

  // 3. Screw Bosses
  let boss_h = height - wall_thickness
  let boss_offset = wall_thickness + boss_diameter / 2.0
  let boss_locs = [
    (boss_offset, boss_offset),
    (width - boss_offset, boss_offset),
    (width - boss_offset, length - boss_offset),
    (boss_offset, length - boss_offset),
  ]
  for i, loc in boss_locs {
    let (bx, by) = loc
    let boss = @cad.tube(boss_diameter, boss_hole_diameter, boss_h)
      .with_name("boss-\{i}")
      .with_color(@cad.Rgb::cyan())
      .translate(x=bx, y=by, z=wall_thickness)
    nodes.push(boss)
  }

  // 4. Lid with Vents
  let vent_w = vent_slot_width
  let vent_s = vent_slot_spacing
  let lid_holes = []

  // Add some vent slots in the middle
  let safe_margin = wall_thickness + boss_diameter + 2.0
  let vent_area_w = width - 2.0 * safe_margin
  let vent_area_l = length - 2.0 * safe_margin
  if vent_area_w > vent_w && vent_area_l > vent_w {
    let num_vents = (vent_area_w / vent_s).to_int()
    for i in 0..