use crate::{interval::Interval, material::Materials, vec3::Point3};

use super::{HitRecord, Hittable};

#[derive(Debug, Clone, Copy)]
pub struct Sphere {
	center: Point3,
	radius: f64,
	material: Materials,
}

impl Sphere {
	pub fn new(center: Point3, radius: f64, material: Materials) -> Self {
		Self { center, radius, material }
	}
}

impl Hittable for Sphere {
	fn hit(&self, ray: &crate::ray::Ray, ray_t: &Interval) -> Option<HitRecord> {
		let oc = self.center - *ray.origin();
		let a = ray.direction().len_squared();
		let h = ray.direction().dot(&oc);
		let c = oc.len_squared() - self.radius * self.radius;
		let discriminant = h * h - a * c;

		if discriminant < 0.0 {
			return None;
		}

		let sqrtd = discriminant.sqrt();

		let mut root = (h - sqrtd) / a;
		if !ray_t.surrounds(root) {
			root = (h + sqrtd) / a;
			if !ray_t.surrounds(root) {
				return None;
			}
		}

		let p = ray.at(root);
		let outward_normal = (p - self.center) / self.radius;
		Some(HitRecord::new(root, p, outward_normal, self.material, ray))
	}
}
