///|
/// 39-analytic-cylinders-and-fits
///
/// A small gauge that demonstrates two kinds of modeling intent:
///
/// - `Cylinder::new` emits analytic cylinders (one `CYLINDRICAL_SURFACE` and
///   two circular caps) instead of a faceted 64-gon.
/// - `Profile2D::hole_with_fit` applies a per-face clearance, so one nominal
///   diameter produces Nominal, Close, Free, and Press holes.
///
/// Four pegs of the nominal diameter sit in front of the plate, one per fit.
/// Export goes through the checked entry point.
///
/// Usage:
///   ./examples/run-example.sh 39 -o fits.step
///   ./examples/run-example.sh 39 --diameter 8 --spacing 16
async fn main {
  let base_args_spec = {
    "diameter": @cli.opt_double(
      10.0,
      short='d',
      help="Nominal hole and pin diameter (mm)",
      min=0.0,
      min_exclusive=true,
    ),
    "thickness": @cli.opt_double(
      5.0,
      help="Plate thickness (mm)",
      min=0.0,
      min_exclusive=true,
    ),
    "pinHeight": @cli.opt_double(
      8.0,
      help="Pin height (mm)",
      min=0.0,
      min_exclusive=true,
    ),
    "spacing": @cli.opt_double(
      20.0,
      help="Hole spacing (mm)",
      min=0.0,
      min_exclusive=true,
    ),
  }
  let args_spec = @cli.with_translate(
    @common.with_output_args(
      base_args_spec,
      out_help="Write STEP output to a file (default: stdout)",
    ),
  )
  guard @cli.parse(
      args_spec,
      prog="39-analytic-cylinders-and-fits",
      description="Generate an analytic cylinder and fit-clearance gauge.",
    )
    is Some(args) else {
    return
  }
  let diameter = args.double("diameter")
  let thickness = args.double("thickness")
  let pin_height = args.double("pinHeight")
  let spacing = args.double("spacing")
  let output = @common.output_paths(args)
  let (tx, ty, tz) = match args.translate_xyz() {
    Some(v) => v
    None => {
      @cli.eprintln("error: invalid translation")
      abort("")
    }
  }
  let fits : Array[(@cad.Fit, String, @cad.Rgb)] = [
    (Nominal, "nominal", @cad.Rgb::grey()),
    (Close, "close", @cad.Rgb::blue()),
    (Free, "free", @cad.Rgb::green()),
    (Press, "press", @cad.Rgb::red()),
  ]

  // Plate with one fitted hole per clearance preset.
  let count = fits.length()
  let plate_width = spacing * Double::from_int(count)
  let plate_depth = 2.0 * spacing
  let holes : Array[Array[@cad.Vec2]] = []
  for i, entry in fits {
    let x = spacing * (Double::from_int(i) + 0.5)
    let y = plate_depth / 2.0
    holes.push(
      @cad.translate_pts(
        @cad.Profile2D::hole_with_fit(diameter, fit=entry.0),
        x,
        y,
      ),
    )
  }
  let mut design = @cad.Design::new(
    name="analytic-fits",
    documentation=args.documentation(),
  ).add(
    @cad.ExtrudedProfile::new(
      @cad.Profile2D::rect(plate_width, plate_depth),
      thickness,
      holes~,
    )
    .with_name("fit-plate")
    .with_color(@cad.Rgb::orange()),
  )

  // One analytic cylinder peg per fit, in front of the plate.
  for i, entry in fits {
    let x = spacing * (Double::from_int(i) + 0.5)
    design = design.add(
      @cad.Cylinder::new(diameter, pin_height)
      .with_name("pin-\{entry.1}")
      .with_color(entry.2)
      .translate(x~, y=-spacing, z=0.0),
    )
  }
  let design = design.translate(x=tx, y=ty, z=tz)
  @common.write_output(design, output, checked=true)
}