use crate::aabb::AABB;
use crate::hitable::Hit;
use crate::hitable::HitRecord;
use crate::ray::Ray;
use crate::vec3::Vec3;

pub struct Translate<H>
where
    H: Hit,
{
    hitable: H,
    offset: Vec3,
}

impl<H> Translate<H>
where
    H: Hit,
{
    pub fn new<V>(hitable: H, offset: V) -> Translate<H>
    where
        V: Into<Vec3>,
    {
        Translate {
            hitable,
            offset: offset.into(),
        }
    }
}

impl<H> Hit for Translate<H>
where
    H: Hit,
{
    fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
        let moved_r = Ray::new(r.origin - self.offset, r.direction, r.time);
        if let Some(rec) = self.hitable.hit(moved_r, t_min, t_max) {
            return Some(HitRecord {
                p: rec.p + self.offset,
                ..rec
            });
        }
        None
    }

    fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
        if let Some(bbox) = self.hitable.bounding_box(t_min, t_max) {
            return Some(AABB::new(
                bbox.min() + self.offset,
                bbox.max() + self.offset,
            ));
        }
        None
    }
}
