use neptunes::rendering::atmosphere_scattering::*;
use neptunes::rendering::clouds::*;
use neptunes::rendering::materials::*;
use neptunes::rendering::ocean_rendering::*;
use neptunes::rendering::shaders::*;

// ── Atmosphere Scattering ────────────────────────────────────────────────

#[test]
fn atmosphere_endpoint_neptune() {
    let ae = AtmosphereEndpoint::neptune();
    assert!(ae.planet_radius_m > 0.0);
    assert!(ae.atmosphere_height_m > 0.0);
    assert!(ae.sun_intensity > 0.0);
}

#[test]
fn sky_luminance_finite() {
    let ae = AtmosphereEndpoint::neptune();
    let l = ae.sky_luminance(0.0, 0.5);
    assert!(l.is_finite() && l >= 0.0);
}

#[test]
fn barometric_density_finite() {
    let ae = AtmosphereEndpoint::neptune();
    let d = ae.barometric_density();
    assert!(d.is_finite() && d > 0.0);
}

#[test]
fn shell_volume_positive() {
    let ae = AtmosphereEndpoint::neptune();
    let v = ae.shell_volume();
    assert!(v.is_finite() && v > 0.0);
}

// ── Clouds ───────────────────────────────────────────────────────────────

#[test]
fn cloud_type_variants() {
    assert!(matches!(CloudType::MethaneIce, CloudType::MethaneIce));
    assert!(matches!(
        CloudType::HydrogenSulfide,
        CloudType::HydrogenSulfide
    ));
    assert!(matches!(
        CloudType::AmmoniaHydrosulfide,
        CloudType::AmmoniaHydrosulfide
    ));
    assert!(matches!(CloudType::DeepWater, CloudType::DeepWater));
    assert!(matches!(
        CloudType::HighAltitudeHaze,
        CloudType::HighAltitudeHaze
    ));
}

#[test]
fn methane_ice_cloud_layer() {
    let cl = CloudLayer::methane_ice();
    assert!(cl.base_altitude_m > 0.0);
    assert!(cl.thickness_m > 0.0);
    assert!(cl.coverage >= 0.0 && cl.coverage <= 1.0);
}

#[test]
fn hydrogen_sulfide_cloud_layer() {
    let cl = CloudLayer::hydrogen_sulfide();
    assert!(cl.thickness_m > 0.0);
}

#[test]
fn ammonia_hydrosulfide_cloud_layer() {
    let cl = CloudLayer::ammonia_hydrosulfide();
    assert!(cl.thickness_m > 0.0);
}

#[test]
fn deep_water_cloud_layer() {
    let cl = CloudLayer::deep_water();
    assert!(cl.thickness_m > 0.0);
}

#[test]
fn high_altitude_haze_layer() {
    let cl = CloudLayer::high_altitude_haze();
    assert!(cl.base_altitude_m > 0.0);
}

#[test]
fn cloud_system_default() {
    let cs = CloudSystemEndpoint::neptune_default();
    assert!(!cs.layers.is_empty());
}

#[test]
fn cloud_system_sample_density() {
    let cs = CloudSystemEndpoint::neptune_default();
    let d = cs.sample_density(50000.0);
    assert!(d.is_finite());
    assert!(d >= 0.0);
}

#[test]
fn cloud_system_wind_transport() {
    let cs = CloudSystemEndpoint::neptune_default();
    let w = cs.wind_transport();
    assert!(w.is_finite());
}

#[test]
fn cloud_system_optical_depth() {
    let cs = CloudSystemEndpoint::neptune_default();
    let od = cs.optical_depth();
    assert!(od.is_finite() && od >= 0.0);
}

#[test]
fn cloud_system_total_thickness() {
    let cs = CloudSystemEndpoint::neptune_default();
    let t = cs.total_thickness();
    assert!(t.is_finite() && t > 0.0);
}

// ── Materials ────────────────────────────────────────────────────────────

#[test]
fn methane_cloud_material() {
    let m = PbrMaterial::methane_cloud();
    assert!(m.roughness >= 0.0 && m.roughness <= 1.0);
    assert!(m.metallic >= 0.0 && m.metallic <= 1.0);
}

#[test]
fn h2s_cloud_material() {
    let m = PbrMaterial::h2s_cloud();
    assert!(m.roughness >= 0.0 && m.roughness <= 1.0);
}

#[test]
fn deep_atmosphere_material() {
    let m = PbrMaterial::deep_atmosphere();
    assert!(m.albedo[3] >= 0.0);
}

#[test]
fn haze_layer_material() {
    let m = PbrMaterial::haze_layer();
    assert!(m.albedo[0] >= 0.0);
}

#[test]
fn core_rock_material() {
    let m = PbrMaterial::core_rock();
    assert!(m.roughness > 0.0);
}

#[test]
fn superionic_ice_material() {
    let m = PbrMaterial::superionic_ice();
    assert!(m.normal_strength >= 0.0);
}

#[test]
fn storm_region_material() {
    let m = PbrMaterial::storm_region();
    assert!(m.albedo[0] >= 0.0);
}

#[test]
fn fresnel_r0_positive() {
    let m = PbrMaterial::methane_cloud();
    let f = m.fresnel_r0();
    assert!(f.is_finite() && (0.0..=1.0).contains(&f));
}

#[test]
fn all_neptune_materials() {
    let all = PbrMaterial::all_neptune();
    assert!(all.len() >= 7);
}

// ── Ocean Rendering ──────────────────────────────────────────────────────

#[test]
fn interior_ocean_default() {
    let io = InteriorOceanEndpoint::superionic_water();
    assert!(io.grid_size > 0);
}

#[test]
fn ocean_fresnel_r0_positive() {
    let io = InteriorOceanEndpoint::superionic_water();
    let f = io.fresnel_r0();
    assert!(f.is_finite() && (0.0..=1.0).contains(&f));
}

#[test]
fn ocean_wave_amplitude_positive() {
    let io = InteriorOceanEndpoint::superionic_water();
    let a = io.wave_amplitude();
    assert!(a.is_finite() && a >= 0.0);
}

#[test]
fn ocean_depth_color_finite() {
    let io = InteriorOceanEndpoint::superionic_water();
    let c = io.depth_color(10.0);
    for ch in &c {
        assert!(ch.is_finite() && *ch >= 0.0);
    }
}

// ── Shaders ──────────────────────────────────────────────────────────────

#[test]
fn shader_terrain() {
    let sd = ShaderEndpoint::terrain();
    assert!(!sd.name.is_empty());
    assert!(!sd.uniforms.is_empty());
}

#[test]
fn shader_atmosphere() {
    let sd = ShaderEndpoint::atmosphere();
    assert!(!sd.name.is_empty());
    assert!(!sd.uniforms.is_empty());
}

#[test]
fn shader_interior_ocean() {
    let sd = ShaderEndpoint::interior_ocean();
    assert!(!sd.name.is_empty());
    assert!(!sd.uniforms.is_empty());
}

#[test]
fn shader_band_dynamics() {
    let sd = ShaderEndpoint::band_dynamics();
    assert!(!sd.name.is_empty());
    assert!(!sd.uniforms.is_empty());
}

#[test]
fn shader_uniform_named_access() {
    let sd = ShaderEndpoint::terrain();
    let first = &sd.uniforms[0];
    assert!(!first.name.is_empty());
    let _v = &first.value;
}

#[test]
fn uniform_value_float() {
    let uv = UniformValue::Float(1.0);
    match uv {
        UniformValue::Float(f) => assert!((f - 1.0).abs() < 1e-6),
        _ => panic!("Expected Float"),
    }
}

#[test]
fn uniform_value_vec3() {
    let uv = UniformValue::Vec3([1.0, 2.0, 3.0]);
    match uv {
        UniformValue::Vec3(v) => assert_eq!(v.len(), 3),
        _ => panic!("Expected Vec3"),
    }
}
