use ray_tracing_core::prelude::*;

pub fn triangle_intersection(ray: Ray, v: [Pos3; 3]) -> Option<Float> {
    let e1 = v[1] - v[0];
    let e2 = v[2] - v[0];

    let ray_cross_e2 = Dir3::cross(ray.dir(), e2);
    let det = e1.dot(ray_cross_e2);

    if det > -f32::EPSILON && det < f32::EPSILON {
        return None; // This ray is parallel to this triangle.
    }

    let inv_det = 1.0 / det;
    let s = ray.start() - v[0];
    let u = inv_det * s.dot(ray_cross_e2);
    if !(0.0..=1.0).contains(&u) {
        return None;
    }

    let s_cross_e1 = s.cross(e1);
    let v = inv_det * Dir3::dot(ray.dir(), s_cross_e1);
    if v < 0.0 || u + v > 1.0 {
        return None;
    }
    // At this stage we can compute t to find out where the intersection point is on the line.
    let t = inv_det * e2.dot(s_cross_e1);

    if t > Float::EPSILON {
        // ray intersection
        Some(t)
    } else {
        // This means that there is a line intersection but not a ray intersection.
        None
    }
}

pub fn triangle_normal(v: [Pos3; 3]) -> Dir3 {
    let e1 = v[1] - v[0];
    let e2 = v[2] - v[0];

    Dir3::cross(e1, e2)
}
