const vec = @import("./vec.zig");
const ray = @import("./ray.zig");
const hittable = @import("./hittable.zig");

const Material = @import("./material.zig").Material;

const Vec3 = vec.Vec3;
const Point3 = vec.Point3;
const Ray = ray.Ray;
const HitRecord = hittable.HitRecord;

pub const Sphere = struct {
    center: Point3,
    radius: f32,
    material: Material,

    pub fn init(center: Point3, radius: f32, material: Material) Sphere {
        return Sphere{
            .center = center,
            .radius = radius,
            .material = material,
        };
    }
    pub fn hit(sphere: Sphere, r: Ray, t_min: f32, t_max: f32) ?HitRecord {
        const center = sphere.center;
        const radius = sphere.radius;
        const oc = r.origin().sub(center);
        const a = r.direction().length_squared();
        const half_b = Vec3.dot(oc, r.direction());
        const c = oc.length_squared() - radius * radius;

        const discriminant = half_b * half_b - a * c;
        if (discriminant < 0) return null;

        const sqrtd = @sqrt(discriminant);

        // Find the nearest root that lies in the acceptable range.
        var root = (-half_b - sqrtd) / a;

        if ((root < t_min) or (t_max < root)) {
            root = (-half_b + sqrtd) / a;
            if ((root < t_min) or (t_max < root)) return null;
        }
        const p = r.at(root);
        const outward_normal = p.sub(center).scale(1 / radius);
        var hr = HitRecord{
            .t = root,
            .p = p,
            .normal = Vec3.init(0, 0, 0),
            .front_face = false,
            .material = sphere.material,
        };
        hr.set_face_normal(r, outward_normal);
        return hr;
    }
};
