use crate::core::geometry::{Bounds3f, Normal3f, Point2f, Point2i, Point3f, Ray, Vector3f};
use crate::core::image::Image;
use crate::core::light::{
    LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait, LightType,
};
use crate::core::medium::MediumInterface;
use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths};
use crate::utils::math::equal_area_sphere_to_square;
use crate::utils::sampling::PiecewiseConstant2D;
use crate::utils::{Ptr, Transform};
use crate::{Float, PI};

#[derive(Debug, Clone, Copy)]
pub struct GoniometricLight {
    pub base: LightBase,
    pub iemit: Ptr<DenselySampledSpectrum>,
    pub scale: Float,
    pub image: Ptr<Image>,
    pub distrib: Ptr<PiecewiseConstant2D>,
}

impl GoniometricLight {
    pub fn i(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum {
        let uv = equal_area_sphere_to_square(w);
        self.scale * self.iemit.sample(lambda) * self.image.lookup_nearest_channel(uv, 0)
    }
}

impl LightTrait for GoniometricLight {
    fn base(&self) -> &LightBase {
        &self.base
    }

    fn sample_li(
        &self,
        _ctx: &LightSampleContext,
        _u: Point2f,
        _lambda: &SampledWavelengths,
        _allow_incomplete_pdf: bool,
    ) -> Option<LightLiSample> {
        todo!()
    }

    fn pdf_li(
        &self,
        _ctx: &LightSampleContext,
        _wi: Vector3f,
        _allow_incomplete_pdf: bool,
    ) -> Float {
        0.
    }

    fn l(
        &self,
        _p: Point3f,
        _n: Normal3f,
        _uv: Point2f,
        _w: Vector3f,
        _lambda: &SampledWavelengths,
    ) -> SampledSpectrum {
        todo!()
    }
    fn le(&self, _ray: &Ray, _lambda: &SampledWavelengths) -> SampledSpectrum {
        todo!()
    }

    #[cfg(not(target_os = "cuda"))]
    fn preprocess(&mut self, _scene_bounds: &Bounds3f) {
        todo!()
    }

    #[cfg(not(target_os = "cuda"))]
    fn bounds(&self) -> Option<LightBounds> {
        todo!()
    }

    #[cfg(not(target_os = "cuda"))]
    fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum {
        let resolution = self.image.resolution();
        let mut sum_y = 0.;
        for y in 0..resolution.y() {
            for x in 0..resolution.x() {
                sum_y += self.image.get_channel(Point2i::new(x, y), 0);
            }
        }
        self.scale * self.iemit.sample(&lambda) * 4. * PI * sum_y
            / (resolution.x() * resolution.y()) as Float
    }
}
