use std::sync::Arc;

use log::info;

use crate::{
    camera::Camera,
    glowybox::Glowybox,
    hitable::Hit,
    hitable_list::HitableList,
    kdtree::KDTree,
    material::{DiffuseLight, Lambertian},
    rect::{XYRect, XZRect, YZRect},
    renderer::{Opt, Scene},
    sphere::Sphere,
    texture::ConstantTexture,
    vec3::Vec3,
};

pub fn new(opt: &Opt) -> Scene {
    let lookfrom = Vec3::new(20., 20., 20.);
    let lookat = Vec3::new(0., 1., 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.),
        20.,
        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, 1.0, 0.4))
    };

    let lights: Vec<Box<dyn Hit>> = vec![
        Box::new(XZRect::new(
            -100.,
            100.,
            -100.,
            1000.,
            60.,
            DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 1., 1.))),
        )),
        Box::new(YZRect::new(
            1.,
            3.,
            -1.,
            1.,
            4.,
            DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 0., 4.))),
        )),
        Box::new(YZRect::new(
            1.,
            3.,
            -1.,
            1.,
            -4.,
            DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 0.))),
        )),
        Box::new(XZRect::new(
            -1.,
            1.,
            -1.,
            1.,
            6.,
            DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 4., 0.))),
        )),
        Box::new(XYRect::new(
            -1.,
            1.,
            1.,
            3.,
            -4.,
            DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 0., 4.))),
        )),
        Box::new(XYRect::new(
            -1.,
            1.,
            1.,
            3.,
            4.,
            DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 4.))),
        )),
    ];
    let mut objects: Vec<Box<dyn Hit>> = vec![
        // Earth sized sphere
        Box::new(Sphere::new(
            Vec3::new(0., -1010., 0.),
            1000.,
            Lambertian::new(ground_color),
        )),
        Box::new(Glowybox::new(
            [-4., -4., -4.].into(),
            [4., 4., 4.].into(),
            0.01,
            Arc::new(Lambertian::new(ConstantTexture::new([0., 0., 0.]))),
            Arc::new(DiffuseLight::new(ConstantTexture::new([100., 0., 0.]))),
        )),
    ];
    objects.extend(lights);
    info!("objects {:?}", objects);
    let world: Box<dyn Hit> = if opt.use_accel {
        Box::new(KDTree::new(objects, time_min, time_max))
    } else {
        Box::new(HitableList::new(objects))
    };
    Scene {
        camera,
        world,
        subsamples: opt.subsamples,
        num_threads: opt.num_threads,
        width: opt.width,
        height: opt.height,
        ..Default::default()
    }
}
