use sciforge::hub::prelude::constants::elements::{atomic_mass, electronegativity};

#[derive(Debug, Clone)]
pub struct PbrMaterial {
    pub name: &'static str,
    pub albedo: [f32; 4],
    pub roughness: f32,
    pub metallic: f32,
    pub normal_strength: f32,
    pub emissive: [f32; 3],
    pub ior: f32,
    pub subsurface: f32,
}

fn metallic_from_iron(fe_wt_frac: f64) -> f32 {
    let m_fe = atomic_mass(26);
    let m_o = atomic_mass(8);
    let fe_fraction_in_feo = m_fe / (m_fe + m_o);
    let pure_fe = fe_wt_frac * fe_fraction_in_feo;
    let en = electronegativity(26).unwrap_or(1.83);
    let metallic_scale = (1.0 - en / 4.0).max(0.0);
    (pure_fe * metallic_scale).clamp(0.0, 1.0) as f32
}

impl PbrMaterial {
    pub fn methane_cloud() -> Self {
        Self {
            name: "methane_cloud",
            albedo: [0.65, 0.72, 0.82, 0.7],
            roughness: 0.2,
            metallic: 0.0,
            normal_strength: 0.3,
            emissive: [0.0; 3],
            ior: 1.31,
            subsurface: 0.6,
        }
    }

    pub fn h2s_cloud() -> Self {
        Self {
            name: "h2s_cloud",
            albedo: [0.45, 0.50, 0.55, 0.8],
            roughness: 0.4,
            metallic: 0.0,
            normal_strength: 0.5,
            emissive: [0.0; 3],
            ior: 1.40,
            subsurface: 0.3,
        }
    }

    pub fn deep_atmosphere() -> Self {
        Self {
            name: "deep_atmosphere",
            albedo: [0.02, 0.05, 0.15, 1.0],
            roughness: 0.1,
            metallic: 0.01,
            normal_strength: 0.2,
            emissive: [0.0; 3],
            ior: 1.00013,
            subsurface: 0.0,
        }
    }

    pub fn haze_layer() -> Self {
        Self {
            name: "haze_layer",
            albedo: [0.55, 0.60, 0.75, 0.3],
            roughness: 0.1,
            metallic: 0.0,
            normal_strength: 0.1,
            emissive: [0.0; 3],
            ior: 1.29,
            subsurface: 0.8,
        }
    }

    pub fn core_rock() -> Self {
        Self {
            name: "core_rock",
            albedo: [0.25, 0.20, 0.15, 1.0],
            roughness: 0.95,
            metallic: metallic_from_iron(0.15),
            normal_strength: 1.0,
            emissive: [0.0; 3],
            ior: 1.54,
            subsurface: 0.0,
        }
    }

    pub fn superionic_ice() -> Self {
        Self {
            name: "superionic_ice",
            albedo: [0.40, 0.55, 0.70, 0.9],
            roughness: 0.05,
            metallic: 0.3,
            normal_strength: 0.4,
            emissive: [0.01, 0.02, 0.05],
            ior: 1.31,
            subsurface: 0.9,
        }
    }

    pub fn storm_region() -> Self {
        Self {
            name: "storm_region",
            albedo: [0.10, 0.12, 0.20, 1.0],
            roughness: 0.3,
            metallic: 0.0,
            normal_strength: 0.8,
            emissive: [0.0; 3],
            ior: 1.00013,
            subsurface: 0.0,
        }
    }

    pub fn fresnel_r0(&self) -> f64 {
        let n = self.ior as f64;
        ((n - 1.0) / (n + 1.0)).powi(2)
    }

    pub fn all_neptune() -> Vec<Self> {
        vec![
            Self::methane_cloud(),
            Self::h2s_cloud(),
            Self::deep_atmosphere(),
            Self::haze_layer(),
            Self::core_rock(),
            Self::superionic_ice(),
            Self::storm_region(),
        ]
    }
}
