// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// Picking and collision: a ray into a small scene, the same ray narrowed down by
/// a sphere test and then a triangle test, and a ball bouncing off a wall.
///
///     moon run src/examples/04-collision
#coverage.skip
fn main {
  let floor = @moonmath.Plane::new(@moonmath.Vec3::unit_y(), 0.0)
  let wall = @moonmath.Plane::new(@moonmath.Vec3::new(0.0, 0.0, -1.0), 5.0)

  let from = @moonmath.Vec3::new(0.0, 2.0, 0.0)
  let aim = @moonmath.Vec3::new(0.3, 0.3, -1.7)
  let ray = @moonmath.Ray3::new(from, (aim - from).normalize())
  println("ray: \{ray}")
  match ray.intersect_plane(wall) {
    Some(t) => println("wall at \{ray.at(t)}")
    None => println("the ray never reaches the wall")
  }
  match ray.intersect_plane(floor) {
    Some(t) => println("floor at \{ray.at(t)}")
    None => println("the ray never reaches the floor")
  }

  println("\n-- narrowing down")
  // A bounding sphere first: cheap, and it throws out what it can.
  let ball = @moonmath.Sphere::new(@moonmath.Vec3::new(0.5, 0.5, -2.0), 1.2)
  println("sphere: \{ball}")
  match ray.intersect_sphere(ball) {
    Some(t) => println("the ray enters the sphere's box at t = \{t}")
    None => println("no sphere to look at")
  }
  // Then the triangles inside it.
  let mesh = [
    @moonmath.Triangle::new(
      @moonmath.Vec3::new(0.0, 0.0, -1.0),
      @moonmath.Vec3::new(1.0, 0.0, -2.0),
      @moonmath.Vec3::new(0.0, 1.0, -2.0),
    ),
    @moonmath.Triangle::new(
      @moonmath.Vec3::new(1.0, 0.0, -2.0),
      @moonmath.Vec3::new(1.0, 1.0, -3.0),
      @moonmath.Vec3::new(0.0, 1.0, -2.0),
    ),
  ]
  let mut nearest : Float = 1.0e9
  let mut hit_any = false
  for triangle in mesh {
    match ray.intersect_triangle(triangle) {
      Some(t) => {
        hit_any = true
        if t < nearest {
          nearest = t
        }
      }
      None => ()
    }
  }
  if hit_any {
    println("nearest triangle at \{ray.at(nearest)}")
    println("its normal faces \{mesh[0].normal()}")
  } else {
    println("the ray passes through the mesh")
  }

  println("\n-- one bounce off the wall, then one off the floor")
  let thrown = @moonmath.Vec3::new(0.0, 2.0, 0.0)
  let thrown_at = @moonmath.Vec3::new(3.0, -1.0, -4.0).normalize()
  match @moonmath.Ray3::new(thrown, thrown_at).intersect_plane(wall) {
    Some(t) => {
      let contact = thrown + thrown_at.scale(t)
      // The wall faces +z, so its normal is the plane's own.
      let away = thrown_at.reflect(wall.normal)
      println("the ball meets the wall at \{contact}")
      println("and leaves along \{away}")
      match @moonmath.Ray3::new(contact, away).intersect_plane(floor) {
        Some(t) => println("it lands at \{(contact + away.scale(t))}")
        None => println("it never comes down")
      }
    }
    None => println("it misses the wall")
  }
}