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

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

const Point3 = vec.Point3;
const Vec3 = vec.Vec3;
const random_in_unit_disk = vec.random_in_unit_disk;
const math = std.math;
const pi = math.pi;
const tan = math.tan;

// Utility Functions

fn degrees_to_radians(degrees: f32) f32 {
    return degrees * pi / 180.0;
}

pub const Camera = struct {
    origin: Point3,
    lower_left_corner: Point3,
    horizontal: Vec3,
    vertical: Vec3,
    u: Vec3,
    v: Vec3,
    w: Vec3,
    lens_radius: f32,

    pub fn init(
        lookfrom: Point3,
        lookat: Point3,
        vup: Vec3,
        vfov: f32, // vertical field-of-view in degrees
        aspect_ratio: f32,
        aperature: f32,
        focus_dist: f32,
    ) Camera {
        const theta = degrees_to_radians(vfov);
        const h = tan(theta / 2);
        const viewport_height = 2 * h;
        const viewport_width = aspect_ratio * viewport_height;

        const w = lookfrom.sub(lookat).unit();
        const u = vup.cross(w).unit();
        const v = w.cross(u);

        const origin = lookfrom;
        const horizontal = u.scale(focus_dist * viewport_width);
        const vertical = v.scale(focus_dist * viewport_height);
        const lower_left_corner = origin.sub(horizontal.scale(0.5)).sub(vertical.scale(0.5)).sub(w.scale(focus_dist));

        const lens_radius = aperature / 2;

        return Camera{
            .origin = origin,
            .horizontal = horizontal,
            .vertical = vertical,
            .lower_left_corner = lower_left_corner,
            .u = u,
            .v = v,
            .w = w,
            .lens_radius = lens_radius,
        };
    }
    pub fn get_ray(camera: Camera, s: f32, t: f32) Ray {
        const rd = random_in_unit_disk().scale(camera.lens_radius);
        const offset = camera.u.scale(rd.x()).add(camera.v.scale(rd.y()));
        return Ray.init(camera.origin.add(offset), camera.lower_left_corner.add(camera.horizontal.scale(s).add(camera.vertical.scale(t).sub(camera.origin).sub(offset))));
    }
};
