use crate::{ray::Ray, raytracer::random_f64, vec3::Color};

use super::Material;

#[derive(Debug, Clone, Copy)]
pub struct Dielectric {
	refraction_index: f64,
}

impl Dielectric {
	pub fn new(refraction_index: f64) -> Self {
		Self { refraction_index }
	}

	fn reflectance(refraction_index: f64, cos: f64) -> f64 {
		let mut r0 = (1.0 - refraction_index) / (1.0 + refraction_index);
		r0 *= r0;
		r0 + (1.0 - r0) * (1.0 - cos).powi(5)
	}
}

impl Material for Dielectric {
	fn scatter(
		&self,
		r_in: &crate::ray::Ray,
		hit_record: &crate::hittable::HitRecord,
	) -> Option<(crate::vec3::Color, crate::ray::Ray)> {
		let attenuation = Color::new(1.0, 1.0, 1.0);
		let ri = match hit_record.front_face {
			true => 1.0 / self.refraction_index,
			false => self.refraction_index,
		};

		let unit_direction = r_in.direction().unit_vector();
		let cos_theta = (-unit_direction).dot(&hit_record.normal).min(1.0);
		let sin_theta = (1.0 - cos_theta * cos_theta).sqrt();

		let cannot_refract = ri * sin_theta > 1.0;

		let direction = match cannot_refract || Self::reflectance(cos_theta, ri) > random_f64() {
			true => unit_direction.reflect(hit_record.normal),
			false => unit_direction.refract(hit_record.normal, ri),
		};

		Some((attenuation, Ray::new(hit_record.p, direction)))
	}
}
