use super::ExampleScene;
use crate::{basic_scene::BasicScene, examples::ExampleSceneEnum};
use ray_tracing_core::prelude::*;
use std::{
    cell::{Cell, OnceCell},
    sync::Arc,
};

pub struct SphereScene<R: Rng, M> {
    scene: OnceCell<BasicScene<Arc<dyn Material<R>>>>,
    material: Cell<Option<M>>,
}

impl<R: Rng, M> SphereScene<R, M> {
    pub fn new(material: M) -> Self {
        Self {
            scene: OnceCell::new(),
            material: Cell::new(Some(material)),
        }
    }
}

impl<R, M> ExampleScene<R> for SphereScene<R, M>
where
    R: Rng + 'static,
    M: Material<R> + Clone + 'static,
    M: Send + Sync,
{
    fn get_scene(&self) -> ExampleSceneEnum<R> {
        let s = self
            .scene
            .get_or_init(|| BasicScene::new(Arc::new(self.material.take().unwrap())));

        ExampleSceneEnum::BasicScene(s.clone())
    }

    fn get_camera_pos(&self) -> Pos3 {
        Pos3::new(5.0, 1.0, 0.0)
    }

    fn get_camera_look_at(&self) -> Pos3 {
        Pos3::new(0.0, 0.0, 0.0)
    }

    fn get_camera_up(&self) -> Dir3 {
        Dir3::up()
    }

    fn get_horizontal_fov(&self) -> Float {
        Float::to_radians(90.0)
    }
}
