use mercurys::rendering::atmosphere_scattering::{
    mie_coefficient, optical_depth, rayleigh_coefficients, scattering_coefficients, sky_color,
    sodium_glow_intensity,
};
use mercurys::rendering::clouds::{cloud_coverage, cloud_optical_depth, has_clouds};
use mercurys::rendering::materials::{PbrMaterial, albedo, roughness};
use mercurys::rendering::ocean_rendering::{
    has_oceans as render_has_oceans, ocean_fraction, specular_reflection, wave_amplitude,
};
use mercurys::rendering::shaders::{ShaderConfig, ShaderPass, shader_id};

// ── Atmosphere Scattering ──

#[test]
fn scattering_coefficients_positive() {
    let (r, m) = scattering_coefficients();
    assert!(r >= 0.0 && m >= 0.0);
}

#[test]
fn rayleigh_coefficients_finite() {
    let c = rayleigh_coefficients();
    for v in &c {
        assert!(v.is_finite());
    }
}

#[test]
fn mie_coefficient_finite() {
    assert!(mie_coefficient().is_finite());
}

#[test]
fn optical_depth_increases_with_zenith() {
    let od_low = optical_depth(0.0, 1.0);
    let od_high = optical_depth(0.0, 0.3);
    assert!(od_high >= od_low);
}

#[test]
fn sky_color_finite() {
    let c = sky_color(0.5);
    for v in &c {
        assert!(v.is_finite());
    }
}

#[test]
fn sodium_glow_stronger_closer() {
    let close = sodium_glow_intensity(0.307);
    let far = sodium_glow_intensity(0.467);
    assert!(close >= far);
}

// ── Clouds ──

#[test]
fn no_clouds_on_mercury() {
    assert!(!has_clouds());
}

#[test]
fn cloud_coverage_zero() {
    assert_eq!(cloud_coverage(), 0.0);
}

#[test]
fn cloud_optical_depth_zero() {
    assert_eq!(cloud_optical_depth(), 0.0);
}

// ── Materials ──

#[test]
fn default_regolith_albedo_dark() {
    let m = PbrMaterial::default_regolith();
    assert!(m.albedo[0] < 0.3);
}

#[test]
fn smooth_plains_different_from_regolith() {
    let reg = PbrMaterial::default_regolith();
    let sp = PbrMaterial::smooth_plains();
    assert!(
        (reg.albedo[0] - sp.albedo[0]).abs() > 0.001
            || (reg.roughness - sp.roughness).abs() > 0.001
    );
}

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

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

#[test]
fn hollows_material_bright() {
    let m = PbrMaterial::hollows();
    let reg = PbrMaterial::default_regolith();
    assert!(m.albedo[0] > reg.albedo[0], "Hollows are bright features");
}

#[test]
fn polar_ice_material_bright() {
    let m = PbrMaterial::polar_ice();
    assert!(m.albedo[0] > 0.5);
}

#[test]
fn thermal_emission_increases_with_temp() {
    let m = PbrMaterial::default_regolith();
    let e400 = m.thermal_emission(400.0);
    let e700 = m.thermal_emission(700.0);
    let sum400: f32 = e400.iter().sum();
    let sum700: f32 = e700.iter().sum();
    assert!(sum700 > sum400);
}

#[test]
fn global_albedo_value() {
    let a = albedo();
    assert!(a > 0.0 && a < 0.3);
}

#[test]
fn global_roughness_value() {
    let r = roughness();
    assert!(r > 0.0 && r <= 1.0);
}

// ── Ocean Rendering ──

#[test]
fn no_oceans_render() {
    assert!(!render_has_oceans());
}

#[test]
fn ocean_fraction_zero_render() {
    assert_eq!(ocean_fraction(), 0.0);
}

#[test]
fn wave_amplitude_zero() {
    assert_eq!(wave_amplitude(), 0.0);
}

#[test]
fn specular_reflection_finite() {
    assert!(specular_reflection().is_finite());
}

// ── Shaders ──

#[test]
fn shader_id_non_empty() {
    let id = shader_id();
    assert!(!id.is_empty());
}

#[test]
fn mercury_surface_shader_no_atmosphere() {
    let cfg = ShaderConfig::mercury_surface();
    assert!(!cfg.has_atmosphere);
    assert!(!cfg.has_ocean);
    assert!(!cfg.has_clouds);
}

#[test]
fn mercury_nightside_thermal() {
    let cfg = ShaderConfig::mercury_nightside();
    assert!(cfg.thermal_overlay);
}

#[test]
fn active_features_surface() {
    let cfg = ShaderConfig::mercury_surface();
    let features = cfg.active_features();
    assert!(features.contains(&"normal_mapping") || cfg.normal_mapping);
}

#[test]
fn shader_pass_variants_exist() {
    let passes = [
        ShaderPass::Depth,
        ShaderPass::Color,
        ShaderPass::Shadow,
        ShaderPass::Thermal,
    ];
    assert_eq!(passes.len(), 4);
    assert_ne!(passes[0], passes[1]);
    assert_ne!(passes[2], passes[3]);
}
