use std::{
    io::{BufReader, Cursor},
    sync::Arc,
};

use stl::STL;

use crate::{
    bvh_triangles::BVHTriangles,
    camera::Camera,
    cuboid::Cuboid,
    hitable::Hit,
    hitable_list::HitableList,
    kdtree::KDTree,
    material::{Dielectric, Lambertian},
    renderer::{Opt, Scene},
    sphere::Sphere,
    texture::{ConstantTexture, EnvMap},
    vec3::Vec3,
};

pub fn new(opt: &Opt) -> Scene {
    let lookfrom = Vec3::new(0., 40., -100.);
    let lookat = Vec3::new(0., 10., 0.);
    let dist_to_focus = 10.0;
    let aperture = 0.0;
    let time_min = 0.;
    let time_max = 1.;
    let camera = Camera::new(
        lookfrom,
        lookat,
        Vec3::new(0., 1., 0.),
        45.,
        opt.width as f32 / opt.height as f32,
        aperture,
        dist_to_focus,
        time_min,
        time_max,
    );
    let ground_color = if opt.use_accel {
        ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))
    } else {
        ConstantTexture::new(Vec3::new(0.4, 0.4, 0.4))
    };

    let stl_cube = STL::parse(
        BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))),
        false,
    )
    .expect("failed to parse cube");
    let _light_size = 50.;
    let _light_height = 200.;
    let objects: Vec<Box<dyn Hit>> = vec![
        // Light from above - white
        // Earth sized sphere
        Box::new(Sphere::new(
            Vec3::new(0., -10000., 0.),
            10000.,
            Lambertian::new(ground_color),
        )),
        // Blue sphere
        Box::new(Sphere::new(
            Vec3::new(0., 20., 40.),
            20.,
            Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.2, 1.))),
        )),
        Box::new(Sphere::new(
            Vec3::new(40., 20., 40.),
            20.,
            //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
            Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 1.0, 0.2))),
        )),
        Box::new(Sphere::new(
            Vec3::new(-40., 20., 40.),
            20.,
            //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
            Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
        )),
        // STL Mesh
        Box::new(BVHTriangles::new(
            &stl_cube,
            Dielectric::new(1.5),
            //Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
            //Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
        )),
        Box::new(Cuboid::new(
            [-20., 0., 0.].into(),
            [0., 20., 20.].into(),
            Arc::new(Dielectric::new(1.5)),
        )),
    ];
    let world: Box<dyn Hit> = if opt.use_accel {
        Box::new(KDTree::new(objects, time_min, time_max))
    } else {
        Box::new(HitableList::new(objects))
    };
    let skybox_bytes = include_bytes!("../../images/envmap.jpg");
    let skybox = image::load_from_memory(skybox_bytes).unwrap().to_rgb();
    Scene {
        camera,
        world,
        subsamples: opt.subsamples,
        num_threads: opt.num_threads,
        width: opt.width,
        height: opt.height,
        global_illumination: true,
        env_map: Some(EnvMap::new(skybox)),
        ..Default::default()
    }
}
