///|
/// 20-arduino-shield-standoff-frame
///
/// A working example that generates a STEP model for: A standoff frame that
/// supports stacked boards with computed clearances.
///
/// Usage (stdout):
///   moon run --target native examples/20-arduino-shield-standoff-frame -- --standoffHeight 10 > arduino-frame.step
async fn main {
  let base_args_spec = {
    "frameThickness": @cli.opt_double(
      3.0,
      help="Thickness of the base frame (mm)",
      min=1.0,
    ),
    "standoffHeight": @cli.opt_double(
      10.0,
      help="Height of the standoffs (mm)",
      min=1.0,
    ),
    "standoffOD": @cli.opt_double(
      6.0,
      help="Outer diameter of standoffs (mm)",
      min=1.0,
    ),
    "standoffID": @cli.opt_double(
      3.2,
      help="Inner hole diameter of standoffs (mm)",
      min=0.5,
    ),
  }
  let args_spec = @cli.with_translate(@common.with_output_args(base_args_spec))
  guard @cli.parse(
      args_spec,
      prog="20-arduino-shield-standoff-frame",
      description="Generate an Arduino Uno standoff frame STEP model.",
    )
    is Some(args) else {
    return
  }
  let frame_thickness = args.double("frameThickness")
  let standoff_height = args.double("standoffHeight")
  let standoff_od = args.double("standoffOD")
  let standoff_id = args.double("standoffID")
  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 = arduino_uno_standoff_frame(
    frame_thickness, standoff_height, standoff_od, standoff_id,
  )
  let mut design = @cad.Design::new(
    name="arduino-standoff-frame",
    documentation=args.documentation(),
  )
  for node in nodes {
    // Center the board area approximately
    design = design.add(
      node.translate(x=tx - 68.6 / 2.0, y=ty - 53.3 / 2.0, z=tz),
    )
  }
  @common.write_output(design, output)
}

///|
fn arduino_uno_standoff_frame(
  frame_thickness : Double,
  standoff_height : Double,
  standoff_diameter : Double,
  standoff_hole_diameter : Double,
) -> Array[@cad.SceneNode] {
  let uno_w = 68.6
  let uno_l = 53.3

  // Increase frame size slightly to support standoffs centered 2.5mm from edge
  let margin = standoff_diameter / 2.0 - 1.5 // Ensure at least 1mm outer support
  let m = if margin < 2.0 { 2.0 } else { margin }
  let width = uno_w + 2.0 * m
  let length = uno_l + 2.0 * m

  // Rail width should be enough to cover the standoff
  let rail_w = standoff_diameter + 2.0
  let outer = @cad.Profile2D::rounded_rect(width, length, 3.0)
  let inner = @cad.Profile2D::rounded_rect(
      width - 2.0 * rail_w,
      length - 2.0 * rail_w,
      2.0,
    )
    .map(fn(p) { (p.0 + rail_w, p.1 + rail_w) })
    .rev()
  let base_frame = @cad.ExtrudedProfile::new(outer, frame_thickness, holes=[
      inner,
    ])
    .with_name("frame")
    .with_color(@cad.Rgb::blue())
    .translate(x=-m, y=-m, z=0.0)
  let nodes = [base_frame]

  // Arduino Uno standard hole pattern (approximate mm from bottom-left corner of board)
  let hole_locs = [(14.0, 2.5), (15.3, 50.8), (66.1, 7.6), (66.1, 35.6)]
  for _, loc in hole_locs {
    let (hx, hy) = loc
    let standoff = @cad.tube(
        standoff_diameter, standoff_hole_diameter, standoff_height,
      )
      .with_name("standoff-{i}")
      .with_color(@cad.Rgb::cyan())
      .translate(x=hx, y=hy, z=frame_thickness)
    nodes.push(standoff)
  }
  nodes
}