///|
/// Interactive CLI entry point and demonstration for moon_binpack.
fn main {
  println("==================================================================")
  println("  moon_binpack: Industrial-grade 2D Rectangle Bin Packing Engine  ")
  println("==================================================================")
  println("")

  let bin_w = 256
  let bin_h = 256
  let packer = @lib.MaxRectsPacker::new(bin_w, bin_h)

  let items = [
    @lib.Size::new(96, 64),
    @lib.Size::new(64, 96),
    @lib.Size::new(80, 48),
    @lib.Size::new(48, 80),
    @lib.Size::new(64, 64),
    @lib.Size::new(48, 48),
    @lib.Size::new(48, 32),
    @lib.Size::new(32, 48),
    @lib.Size::new(32, 32),
    @lib.Size::new(32, 32),
    @lib.Size::new(24, 24),
    @lib.Size::new(24, 24),
    @lib.Size::new(16, 32),
    @lib.Size::new(32, 16),
    @lib.Size::new(16, 16),
    @lib.Size::new(16, 16),
  ]

  println(
    "Packing " +
    items.length().to_string() +
    " items into " +
    bin_w.to_string() +
    "x" +
    bin_h.to_string() +
    " atlas...",
  )

  let (packed, unpacked) = packer.insert_batch(
    items,
    heuristic=@lib.MaxRectsHeuristic::BestShortSideFit,
    allow_rotation=true,
  )

  let occupancy_pct = (packer.occupancy() * 1000.0).to_int().to_double() / 10.0

  println("Result:")
  println(
    "  - Packed items:   " +
    packed.length().to_string() +
    " / " +
    items.length().to_string(),
  )
  println("  - Unpacked items: " + unpacked.length().to_string())
  println("  - Occupancy:      " + occupancy_pct.to_string() + "%")
  println("")
  println("Layout Frames:")
  println("  [ID]   X    Y    W    H   Rotated")
  println("  ---------------------------------")
  for r in packed {
    let rot_str = if r.rotated { "Yes" } else { "No" }
    println(
      "  #" +
      r.id.to_string() +
      "   " +
      r.x.to_string() +
      "   " +
      r.y.to_string() +
      "   " +
      r.width.to_string() +
      "   " +
      r.height.to_string() +
      "   " +
      rot_str,
    )
  }

  println("")
  let svg = @lib.to_svg(bin_w, bin_h, packed, title="moon_binpack Demo Atlas")
  let css = @lib.to_css(packed, class_prefix="sprite")
  let html = @lib.to_html(
    bin_w,
    bin_h,
    packed,
    title="moon_binpack Interactive Report",
  )
  let csv = @lib.to_csv(packed)
  let pixi = @lib.to_pixi_json(bin_w, bin_h, packed, image_name="atlas.png")

  println("Generated Exporters:")
  println("  - SVG Preview:        " + svg.length().to_string() + " bytes")
  println("  - CSS Sprites:        " + css.length().to_string() + " bytes")
  println("  - HTML Report:        " + html.length().to_string() + " bytes")
  println("  - CSV Layout Data:    " + csv.length().to_string() + " bytes")
  println("  - Pixi.js / Phaser:   " + pixi.length().to_string() + " bytes")

  println("")
  println("Running 18-Heuristic Arena (best_pack across 4 algorithms)...")
  let (best_res, winning_algo) = @lib.best_pack(
    items,
    max_width=512,
    max_height=512,
  )
  let best_pct = (best_res.stats.occupancy * 1000.0).to_int().to_double() / 10.0
  println("  - Winning Heuristic:  " + winning_algo)
  println("  - Allocated Pages:    " + best_res.pages.length().to_string())
  println("  - Packed Items:       " + best_res.rects.length().to_string())
  println("  - Final Occupancy:    " + best_pct.to_string() + "%")

  println("")
  println("Demonstrating Extruded Pixel Texture Baker (Layer 2)...")
  let img1 = @lib.PixelBuffer::new(48, 32, color=@lib.Rgba::from_hex(0xFF4444))
  let img2 = @lib.PixelBuffer::new(32, 48, color=@lib.Rgba::from_hex(0x44FF44))
  let img3 = @lib.PixelBuffer::new(24, 24, color=@lib.Rgba::from_hex(0x4444FF))

  let baker_items = [
    @lib.ImageItem::new(1, img1),
    @lib.ImageItem::new(2, img2),
    @lib.ImageItem::new(3, img3),
  ]

  let baker = @lib.AtlasBaker::new(extrude_margin=1)
  let (baked_pages, baker_winner) = baker.bake_best(baker_items)
  if baked_pages.length() > 0 {
    let p0 = baked_pages[0]
    let bmp = p0.image.to_bmp()
    let tga = p0.image.to_tga()
    println("  - Arena Winning Backend:  " + baker_winner)
    println(
      "  - Baked Atlas Dimensions: " +
      p0.image.width().to_string() +
      "x" +
      p0.image.height().to_string() +
      " px",
    )
    println("  - Extruded Bleeding Margin: 1 px duplicate border")
    println(
      "  - Windows Bitmap (.bmp):   " +
      bmp.length().to_string() +
      " bytes (32-bit uncompressed BMP)",
    )
    println(
      "  - Truevision TGA (.tga):   " +
      tga.length().to_string() +
      " bytes (32-bit uncompressed TGA)",
    )
    if p0.uv_frames.length() > 0 {
      let uv = p0.uv_frames[0]
      let frame0 = p0.frames[0]
      let uv_gl = frame0.to_uv_ex(
        p0.image.width(),
        p0.image.height(),
        half_texel_inset=true,
        flip_v=true,
      )
      println(
        "  - Direct3D/WebGPU UV Inset: [" +
        uv.u_min.to_string() +
        ", " +
        uv.v_min.to_string() +
        "] -> [" +
        uv.u_max.to_string() +
        ", " +
        uv.v_max.to_string() +
        "]",
      )
      println(
        "  - WebGL/OpenGL Flipped UV:  [" +
        uv_gl.u_min.to_string() +
        ", " +
        uv_gl.v_min.to_string() +
        "] -> [" +
        uv_gl.u_max.to_string() +
        ", " +
        uv_gl.v_max.to_string() +
        "]",
      )
    }
  }

  println("")
  println("Done successfully!")
}