///|
/// 05-gridfinity-compatible-bin
///
/// A maker-friendly storage bin generator.
///
/// Usage (stdout):
///   moon run --target native examples/05-gridfinity-compatible-bin -- --rows 2 --cols 1 > bin.step
const GRID_UNIT : Double = 42.0

///|
const WALL_THICKNESS : Double = 2.0

///|
const BASE_THICKNESS : Double = 2.0

///|
async fn main {
  let base_args_spec = {
    "rows": @cli.opt_double(
      1.0,
      help="Number of grid units in Y (rows)",
      min=1.0,
    ),
    "cols": @cli.opt_double(
      1.0,
      help="Number of grid units in X (cols)",
      min=1.0,
    ),
    "height": @cli.opt_double(
      30.0,
      help="Total bin height (mm)",
      min=BASE_THICKNESS + 1.0,
    ),
    "text": @cli.opt_string(help="Label text to engrave"),
    "fontSize": @cli.opt_double(
      0.0,
      help="Font size (mm), default is 60% of wall height",
      min=0.0,
    ),
    "depth": @cli.opt_double(
      0.5,
      help="Engraving depth (mm)",
      min=0.0,
      max=WALL_THICKNESS - 0.1,
    ),
  }
  let args_spec = @cli.with_translate(@common.with_output_args(base_args_spec))
  guard @cli.parse(
      args_spec,
      prog="05-gridfinity-compatible-bin",
      description="Generate a Gridfinity-compatible storage bin.",
    )
    is Some(args) else {
    return
  }
  let rows = args.double("rows").to_int()
  let cols = args.double("cols").to_int()
  let height = args.double("height")
  let text_opt = args.string_opt("text")
  let font_size_opt = args.double("fontSize")
  let emboss_depth = args.double("depth")
  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 total_width = Double::from_int(cols) * GRID_UNIT
  let total_length = Double::from_int(rows) * GRID_UNIT
  let mut design = @cad.Design::new(
    name="gridfinity-bin",
    documentation=args.documentation(),
  )

  // 1. The Base
  let base = @cad.Cuboid::new(total_width, total_length, BASE_THICKNESS)
    .with_name("bin-base")
    .with_color(@cad.Rgb::red())
    .translate(x=tx, y=ty, z=tz)
  design = design.add(base)

  // 2. Outer Walls
  let outer_poly = [
    (0.0, 0.0),
    (total_width, 0.0),
    (total_width, total_length),
    (0.0, total_length),
  ]
  // The hole is wound opposite to the outer boundary.
  let inner_poly = [
    (WALL_THICKNESS, WALL_THICKNESS),
    (total_width - WALL_THICKNESS, WALL_THICKNESS),
    (total_width - WALL_THICKNESS, total_length - WALL_THICKNESS),
    (WALL_THICKNESS, total_length - WALL_THICKNESS),
  ].rev()
  let wall_height = height - BASE_THICKNESS
  let walls = @cad.ExtrudedProfile::new(outer_poly, wall_height, holes=[
      inner_poly,
    ])
    .with_name("bin-walls")
    .with_color(@cad.Rgb::cyan())
    .translate(x=tx, y=ty, z=tz + BASE_THICKNESS)
  design = design.add(walls)

  // 3. Internal Dividers
  for i in 1.. {
      let font = @cad.load_font("baloo")
      if font_size_opt > 0.0 {
        design = design.add_text_on_face(
          walls,
          label,
          Back, // min_y face
          font,
          font_size=font_size_opt,
          emboss_depth~,
          color=@cad.Rgb::orange(),
        )
      } else {
        design = design.add_text_on_face(
          walls,
          label,
          Back, // min_y face
          font,
          emboss_depth~,
          color=@cad.Rgb::orange(),
        )
      }
    }
    None => ()
  }
  @common.write_output(design, output)
}