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

///|
/// Everything the library does, in one run: vectors, matrices, rotations,
/// affine transforms and the geometry.
///
///     moon run src/examples/01-tour

///|
/// A hit along the ray, or the fact that there was none, as text.
fn hit(value : Float?) -> String {
  match value {
    Some(t) => t.to_string()
    None => "no hit"
  }
}

///|
#coverage.skip
fn main {
  println("-- vectors")
  let up = @moonmath.Vec3::unit_y()
  let ahead = @moonmath.Vec3::unit_z()
  println("up x ahead      = \{up.cross(ahead)}")
  println("their angle     = \{up.angle_between(ahead)} rad")
  println("reflected ahead = \{ahead.reflect(up)}")
  println("normalized      = \{@moonmath.Vec3::new(3.0, 0.0, 4.0).normalize()}")

  println("\n-- matrices")
  let projection = @moonmath.Mat4::perspective(
    @moonmath.to_radians(60.0),
    16.0 / 9.0,
    0.1,
    100.0,
  )
  let camera = @moonmath.Mat4::look_at(
    @moonmath.Vec3::new(0.0, 1.0, 5.0),
    @moonmath.Vec3::zero(),
    @moonmath.Vec3::unit_y(),
  )
  let view_projection = projection * camera
  println(
    "origin on screen  = \{view_projection.transform_point(@moonmath.Vec3::zero())}",
  )
  println(
    "one unit right    = \{view_projection.transform_point(@moonmath.Vec3::new(1.0, 0.0, 0.0))}",
  )
  println("determinant       = \{camera.determinant()}")

  println("\n-- rotations")
  let turn = @moonmath.Quat::from_axis_angle(
    @moonmath.Vec3::unit_y(),
    @moonmath.quarter_pi,
  )
  println("quarter turn of x = \{turn.rotate(@moonmath.Vec3::unit_x())}")
  println("its matrix        = \{turn.to_mat3()}")
  let halfway = @moonmath.Quat::identity().slerp(turn, 0.5)
  println("half of the turn  = \{halfway.rotate(@moonmath.Vec3::unit_x())}")

  println("\n-- affine transforms")
  let trs = @moonmath.Trs::new(
    @moonmath.Vec3::new(2.0, 0.0, 0.0),
    turn,
    @moonmath.Vec3::splat(2.0),
  )
  println(
    "scaled, turned, moved = \{@moonmath.Affine3::from_trs(trs).transform_point(@moonmath.Vec3::unit_x())}",
  )
  let back = @moonmath.Mat4::from_trs(trs).to_trs().unwrap()
  println("and taken apart again = \{back}")

  println("\n-- geometry")
  let room = @moonmath.Aabb3::new(
    @moonmath.Vec3::new(-4.0, 0.0, -4.0),
    @moonmath.Vec3::new(4.0, 3.0, 4.0),
  )
  println("room centre  = \{room.center()}")
  println("room volume  = \{room.volume()}")
  let floor = @moonmath.Plane::new(@moonmath.Vec3::unit_y(), 0.0)
  println(
    "floor at y=1 = \{floor.signed_distance(@moonmath.Vec3::new(0.0, 1.0, 0.0))}",
  )
  let ray = @moonmath.Ray3::new(
    @moonmath.Vec3::new(0.0, 2.0, 0.0),
    @moonmath.Vec3::new(0.5, -1.0, 0.0).normalize(),
  )
  println("ray meets floor at   = \{hit(ray.intersect_plane(floor))}")
  println("ray meets the room   = \{hit(ray.intersect_aabb(room))}")
  let sphere = @moonmath.Sphere::new(@moonmath.Vec3::new(0.0, 0.0, -2.0), 0.5)
  println("ray meets the ball   = \{hit(ray.intersect_sphere(sphere))}")
  println("is the ball in the room? = \{room.contains_point(sphere.center)}")
}