use crate::Float;
use crate::bxdfs::{
    CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF,
    MeasuredBxDF, MeasuredBxDFData,
};
use crate::core::bsdf::BSDF;
use crate::core::bssrdf::{BSSRDF, BSSRDFTable};
use crate::core::bxdf::BxDF;
use crate::core::image::Image;
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::textures::GPUSpectrumMixTexture;
use crate::utils::Ptr;
use crate::utils::math::clamp;

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct HairMaterial {
    pub sigma_a: Ptr<GPUSpectrumTexture>,
    pub color: Ptr<GPUSpectrumTexture>,
    pub eumelanin: Ptr<GPUFloatTexture>,
    pub pheomelanin: Ptr<GPUFloatTexture>,
    pub eta: Ptr<GPUFloatTexture>,
    pub beta_m: Ptr<GPUFloatTexture>,
    pub beta_n: Ptr<GPUFloatTexture>,
    pub alpha: Ptr<GPUFloatTexture>,
}

impl HairMaterial {
    #[cfg(not(target_os = "cuda"))]
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        sigma_a: Ptr<GPUSpectrumTexture>,
        color: Ptr<GPUSpectrumTexture>,
        eumelanin: Ptr<GPUFloatTexture>,
        pheomelanin: Ptr<GPUFloatTexture>,
        eta: Ptr<GPUFloatTexture>,
        beta_m: Ptr<GPUFloatTexture>,
        beta_n: Ptr<GPUFloatTexture>,
        alpha: Ptr<GPUFloatTexture>,
    ) -> Self {
        Self {
            sigma_a,
            color,
            eumelanin,
            pheomelanin,
            eta,
            beta_m,
            beta_n,
            alpha,
        }
    }
}

impl MaterialTrait for HairMaterial {
    fn get_bsdf<T: TextureEvaluator>(
        &self,
        _tex_eval: &T,
        _ctx: &MaterialEvalContext,
        _lambda: &SampledWavelengths,
    ) -> BSDF {
        todo!()
    }
    fn get_bssrdf<T>(
        &self,
        _tex_eval: &T,
        _ctx: &MaterialEvalContext,
        _lambda: &SampledWavelengths,
    ) -> Option<BSSRDF> {
        todo!()
    }

    fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool {
        todo!()
    }

    fn get_normal_map(&self) -> Option<&Image> {
        todo!()
    }

    fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
        Ptr::null()
    }

    fn has_subsurface_scattering(&self) -> bool {
        false
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct MeasuredMaterial {
    pub displacement: Ptr<GPUFloatTexture>,
    pub normal_map: Ptr<Image>,
    pub brdf: Ptr<MeasuredBxDFData>,
}

impl MaterialTrait for MeasuredMaterial {
    fn get_bsdf<T: TextureEvaluator>(
        &self,
        _tex_eval: &T,
        _ctx: &MaterialEvalContext,
        _lambda: &SampledWavelengths,
    ) -> BSDF {
        // MeasuredBxDF::new(&self.brdf, lambda)
        todo!()
    }

    fn get_bssrdf<T>(
        &self,
        _tex_eval: &T,
        _ctx: &MaterialEvalContext,
        _lambda: &SampledWavelengths,
    ) -> Option<BSSRDF> {
        None
    }

    fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool {
        true
    }

    fn get_normal_map(&self) -> Option<&Image> {
        Some(&*self.normal_map)
    }

    fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
        self.displacement
    }

    fn has_subsurface_scattering(&self) -> bool {
        false
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct SubsurfaceMaterial {
    pub normal_map: Ptr<Image>,
    pub displacement: Ptr<GPUFloatTexture>,
    pub sigma_a: Ptr<GPUSpectrumTexture>,
    pub sigma_s: Ptr<GPUSpectrumMixTexture>,
    pub reflectance: Ptr<GPUSpectrumMixTexture>,
    pub mfp: Ptr<GPUSpectrumMixTexture>,
    pub eta: Float,
    pub scale: Float,
    pub u_roughness: Ptr<GPUFloatTexture>,
    pub v_roughness: Ptr<GPUFloatTexture>,
    pub remap_roughness: bool,
    pub table: BSSRDFTable,
}

impl MaterialTrait for SubsurfaceMaterial {
    fn get_bsdf<T: TextureEvaluator>(
        &self,
        _tex_eval: &T,
        _ctx: &MaterialEvalContext,
        _lambda: &SampledWavelengths,
    ) -> BSDF {
        todo!()
    }
    fn get_bssrdf<T>(
        &self,
        _tex_eval: &T,
        _ctx: &MaterialEvalContext,
        _lambda: &SampledWavelengths,
    ) -> Option<BSSRDF> {
        todo!()
    }

    fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool {
        todo!()
    }

    fn get_normal_map(&self) -> Option<&Image> {
        todo!()
    }

    fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
        todo!()
    }

    fn has_subsurface_scattering(&self) -> bool {
        true
    }
}
