use mercurys::geology::earthquakes::{
    MercuryQuake, annual_frequency, crust_p_wave_velocity, crust_s_wave_velocity,
    estimated_global_contraction_km, major_scarps, max_expected_magnitude,
    seismic_activity_expected,
};
use mercurys::geology::erosion::{
    SpaceWeathering, cosmogenic_production_rate, equatorial_temp_swing,
    radiogenic_fraction_remaining, thermal_fatigue_crack_growth_rate,
};
use mercurys::geology::mountains::{
    highest_point_estimate_m, isostatic_elevation, lowest_point_estimate_m, major_crater_rims,
    major_scarp_ridges, total_relief_m,
};
use mercurys::geology::plate_tectonics::{
    MercuryInterior, cmb_temperature, lithosphere_thermal_subsidence, mean_heat_flux_mw_m2,
    surface_heat_flow, temperature_at_depth,
};
use mercurys::geology::volcanism::{
    MercuryMagma, MercuryVolcanism, hollow_count, known_hollow_fields,
};

// ── Plate Tectonics / Interior ──

#[test]
fn core_mass_fraction_above_60() {
    let interior = MercuryInterior::new();
    assert!(interior.core_mass_fraction() > 0.6);
}

#[test]
fn core_larger_than_inner_core() {
    let i = MercuryInterior::new();
    assert!(i.core_radius_m > i.inner_core_radius_m);
}

#[test]
fn not_tectonically_active() {
    let i = MercuryInterior::new();
    assert!(!i.is_tectonically_active());
}

#[test]
fn contraction_about_7_km() {
    let i = MercuryInterior::new();
    assert!((i.contraction_estimate_km() - 7.0).abs() < 2.0);
}

#[test]
fn core_volume_positive() {
    let i = MercuryInterior::new();
    assert!(i.core_volume_m3() > 0.0);
}

#[test]
fn inner_core_volume_lt_core() {
    let i = MercuryInterior::new();
    assert!(i.inner_core_volume_m3() < i.core_volume_m3());
}

#[test]
fn mantle_volume_positive() {
    let i = MercuryInterior::new();
    assert!(i.mantle_volume_m3() > 0.0);
}

#[test]
fn crust_volume_positive() {
    let i = MercuryInterior::new();
    assert!(i.crust_volume_m3() > 0.0);
}

#[test]
fn crustal_root_depth_positive() {
    let i = MercuryInterior::new();
    assert!(i.crustal_root_depth(3000.0) > 0.0);
}

#[test]
fn isostatic_elevation_finite() {
    let i = MercuryInterior::new();
    assert!(i.isostatic_elevation().is_finite());
}

#[test]
fn surface_heat_flow_positive() {
    let hf = surface_heat_flow(3.0, 0.01);
    assert!(hf.is_finite());
}

#[test]
fn temperature_increases_with_depth() {
    let t1 = temperature_at_depth(1000.0, 0.01);
    let t2 = temperature_at_depth(10000.0, 0.01);
    assert!(t2 > t1);
}

#[test]
fn cmb_temperature_about_2000() {
    let t = cmb_temperature();
    assert!(t > 1500.0 && t < 2500.0);
}

#[test]
fn thermal_subsidence_positive() {
    let s = lithosphere_thermal_subsidence(50_000.0, 1.0e9, 1.0e-6);
    assert!(s.is_finite());
}

#[test]
fn mean_heat_flux_positive() {
    assert!(mean_heat_flux_mw_m2() > 0.0);
}

// ── Volcanism ──

#[test]
fn volcanism_extinct() {
    let v = MercuryVolcanism::new();
    assert!(!v.currently_active);
}

#[test]
fn volcanic_plains_coverage_high() {
    let v = MercuryVolcanism::new();
    assert!(v.total_volcanic_coverage() > 0.5);
}

#[test]
fn smooth_plains_area_positive() {
    let v = MercuryVolcanism::new();
    assert!(v.smooth_plains_area_km2() > 0.0);
}

#[test]
fn volcanic_vents_positive() {
    let v = MercuryVolcanism::new();
    assert!(v.volcanic_vents_count() > 0);
}

#[test]
fn last_eruption_ancient() {
    let v = MercuryVolcanism::new();
    assert!(v.last_eruption_estimate_gyr() >= 1.0);
}

#[test]
fn intercrater_plains_fraction_reasonable() {
    let v = MercuryVolcanism::new();
    let f = v.intercrater_plains_fraction();
    assert!(f > 0.0 && f < 1.0);
}

#[test]
fn magma_northern_plains_mg_number() {
    let m = MercuryMagma::northern_plains();
    let mg = m.mg_number();
    assert!(mg.is_finite());
}

#[test]
fn magma_high_mg_region() {
    let m = MercuryMagma::high_mg_region();
    assert!(m.mgo_wt_percent > MercuryMagma::northern_plains().mgo_wt_percent);
}

#[test]
fn magma_total_alkali_positive() {
    let m = MercuryMagma::northern_plains();
    assert!(m.total_alkali() > 0.0);
}

#[test]
fn magma_liquidus_temp_finite() {
    let m = MercuryMagma::northern_plains();
    assert!(m.liquidus_temp_c().is_finite());
}

#[test]
fn magma_solidus_depression_finite() {
    let m = MercuryMagma::northern_plains();
    assert!(m.solidus_depression_c().is_finite());
}

#[test]
fn magma_differentiation_idx_finite() {
    let m = MercuryMagma::northern_plains();
    assert!(m.differentiation_idx().is_finite());
}

#[test]
fn olivine_settling_velocity_positive() {
    let m = MercuryMagma::northern_plains();
    let v = m.olivine_settling_velocity(0.001);
    assert!(v.is_finite());
}

#[test]
fn known_hollows_non_empty() {
    let hollows = known_hollow_fields();
    assert!(!hollows.is_empty());
    for h in &hollows {
        assert!(h.depth_m > 0.0 && h.depth_m < 100.0);
    }
}

#[test]
fn hollow_count_matches() {
    assert!(hollow_count() > 0);
}

// ── Earthquakes ──

#[test]
fn major_scarps_non_empty() {
    let scarps = major_scarps();
    assert!(!scarps.is_empty());
}

#[test]
fn scarp_seismic_moment_positive() {
    for s in &major_scarps() {
        assert!(s.estimated_seismic_moment(3.5e10) > 0.0, "{}", s.name);
    }
}

#[test]
fn scarp_magnitude_reasonable() {
    for s in &major_scarps() {
        let mw = s.estimated_magnitude(3.5e10);
        assert!(mw > 3.0 && mw < 12.0, "{} Mw={}", s.name, mw);
    }
}

#[test]
fn quake_from_magnitude_roundtrip() {
    let q = MercuryQuake::from_magnitude(30.0, 120.0, 10.0, 5.0);
    assert!((q.moment_magnitude() - 5.0).abs() < 0.5);
}

#[test]
fn p_wave_arrival_positive() {
    let q = MercuryQuake::from_magnitude(0.0, 0.0, 10.0, 4.0);
    let vp = crust_p_wave_velocity();
    let t = q.p_wave_arrival_s(100.0, vp);
    assert!(t > 0.0);
}

#[test]
fn s_wave_slower_than_p() {
    let q = MercuryQuake::from_magnitude(0.0, 0.0, 10.0, 4.0);
    let vp = crust_p_wave_velocity();
    let vs = crust_s_wave_velocity();
    let tp = q.p_wave_arrival_s(100.0, vp);
    let ts = q.s_wave_arrival_s(100.0, vs);
    assert!(ts > tp);
}

#[test]
fn annual_frequency_decreases() {
    assert!(annual_frequency(3.0) > annual_frequency(5.0));
}

#[test]
fn seismic_activity_expected_true() {
    assert!(seismic_activity_expected());
}

#[test]
fn max_expected_magnitude_reasonable() {
    let m = max_expected_magnitude();
    assert!(m > 3.0 && m < 8.0);
}

#[test]
fn global_contraction_positive() {
    assert!(estimated_global_contraction_km() > 0.0);
}

// ── Mountains / Topography ──

#[test]
fn crater_rims_non_empty() {
    let rims = major_crater_rims();
    assert!(!rims.is_empty());
    assert!(rims.iter().any(|r| r.crater_name == "Caloris"));
}

#[test]
fn rim_heights_positive() {
    for r in &major_crater_rims() {
        assert!(r.rim_height_m > 0.0, "{}", r.crater_name);
    }
}

#[test]
fn crater_depth_to_diameter_positive() {
    for r in &major_crater_rims() {
        assert!(r.depth_to_diameter_ratio() > 0.0, "{}", r.crater_name);
    }
}

#[test]
fn estimated_floor_depth_positive() {
    for r in &major_crater_rims() {
        assert!(r.estimated_floor_depth_m().is_finite(), "{}", r.crater_name);
    }
}

#[test]
fn isostatic_root_positive() {
    for r in &major_crater_rims() {
        assert!(r.isostatic_root_m().is_finite(), "{}", r.crater_name);
    }
}

#[test]
fn scarp_ridges_non_empty() {
    let ridges = major_scarp_ridges();
    assert!(!ridges.is_empty());
    for r in &ridges {
        assert!(r.peak_height_m > 0.0);
    }
}

#[test]
fn total_relief_positive() {
    assert!(total_relief_m() > 0.0);
}

#[test]
fn highest_point_positive() {
    assert!(highest_point_estimate_m() > 0.0);
}

#[test]
fn lowest_point_negative() {
    assert!(lowest_point_estimate_m() < 0.0);
}

#[test]
fn isostatic_elevation_fn_finite() {
    let e = isostatic_elevation(35_000.0);
    assert!(e.is_finite());
}

// ── Erosion / Space Weathering ──

#[test]
fn space_weathering_rates_positive() {
    let sw = SpaceWeathering::new();
    assert!(sw.micrometeorite_flux_rate > 0.0);
    assert!(sw.solar_wind_sputtering_rate > 0.0);
    assert!(sw.npfp_production_rate > 0.0);
}

#[test]
fn regolith_gardening_increases() {
    let sw = SpaceWeathering::new();
    assert!(sw.regolith_gardening_depth_m(100.0e6) > sw.regolith_gardening_depth_m(1.0e6));
}

#[test]
fn surface_darkening_approaches_one() {
    let sw = SpaceWeathering::new();
    assert!(sw.surface_darkening_factor(5000.0) > 0.9);
}

#[test]
fn global_sputtering_rate_positive() {
    let sw = SpaceWeathering::new();
    assert!(sw.global_sputtering_rate_kg_s() > 0.0);
}

#[test]
fn turnover_period_positive() {
    let sw = SpaceWeathering::new();
    assert!(sw.turnover_period_years() > 0.0);
}

#[test]
fn spectral_reddening_positive() {
    let sw = SpaceWeathering::new();
    assert!(sw.spectral_reddening_per_myr() > 0.0);
}

#[test]
fn thermal_fatigue_positive() {
    let rate = thermal_fatigue_crack_growth_rate(equatorial_temp_swing(), 1.0);
    assert!(rate > 0.0);
}

#[test]
fn cosmogenic_production_positive() {
    assert!(cosmogenic_production_rate() > 0.0);
}

#[test]
fn radiogenic_fraction_decays() {
    let f = radiogenic_fraction_remaining(1.0e9, 2.0e9);
    assert!(f.is_finite());
}
