use std::{f32::consts::PI, time::Instant};

use anyhow::Result;

use rtchallenge::{
    camera::Camera,
    lights::PointLight,
    materials::Material,
    matrices::Matrix4x4,
    spheres::Sphere,
    transformations::view_transform,
    tuples::{Color, Tuple},
    world::World,
    WHITE,
};

fn main() -> Result<()> {
    let start = Instant::now();
    let width = 1024;
    let height = 1024;
    let light_position = Tuple::point(-10., 10., -10.);
    let light_color = WHITE;
    let light = PointLight::new(light_position, light_color);
    let mut camera = Camera::new(width, height, PI / 3.);
    let from = Tuple::point(0., 1.5, -5.);
    let to = Tuple::point(0., 1., 0.);
    let up = Tuple::point(0., 1., 0.);
    camera.transform = view_transform(from, to, up);

    let mut floor = Sphere::default();
    floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
    floor.material = Material {
        color: Color::new(1., 0.9, 0.9),
        specular: 0.,
        ..Material::default()
    };

    let mut left_wall = Sphere::default();
    left_wall.set_transform(
        Matrix4x4::translation(0., 0., 5.)
            * Matrix4x4::rotation_y(-PI / 4.)
            * Matrix4x4::rotation_x(PI / 2.)
            * Matrix4x4::scaling(10., 0.01, 10.),
    );
    left_wall.material = floor.material.clone();

    let mut right_wall = Sphere::default();
    right_wall.set_transform(
        Matrix4x4::translation(0., 0., 5.)
            * Matrix4x4::rotation_y(PI / 4.)
            * Matrix4x4::rotation_x(PI / 2.)
            * Matrix4x4::scaling(10., 0.01, 10.),
    );
    right_wall.material = floor.material.clone();

    let mut middle = Sphere::default();
    middle.set_transform(Matrix4x4::translation(-0.5, 1., 0.5));
    middle.material = Material {
        color: Color::new(0.1, 1., 0.5),
        diffuse: 0.7,
        specular: 0.3,
        ..Material::default()
    };

    let mut right = Sphere::default();
    right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5));
    right.material = Material {
        color: Color::new(0.5, 1., 0.1),
        diffuse: 0.7,
        specular: 0.3,
        ..Material::default()
    };

    let mut left = Sphere::default();
    left.set_transform(
        Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33),
    );
    left.material = Material {
        color: Color::new(1., 0.8, 0.1),
        diffuse: 0.7,
        specular: 0.3,
        ..Material::default()
    };

    let mut world = World::default();
    world.light = Some(light);
    world.objects = vec![floor, left_wall, right_wall, middle, right, left];

    let image = camera.render(&world);

    let path = "/tmp/eoc7.png";
    println!("saving output to {}", path);
    image.write_to_file(path)?;
    println!("Render time {:.2} seconds", start.elapsed().as_secs_f32());
    Ok(())
}
