use mercurys::satellites::artificial::{all_missions, bepicolombo_mmo, bepicolombo_mpo, messenger};
use mercurys::satellites::none::{
    absence_reasons, has_natural_satellite, hill_sphere_radius_m, natural_satellite_count,
};

// ── No Natural Satellites ──

#[test]
fn no_natural_satellites() {
    assert!(!has_natural_satellite());
}

#[test]
fn satellite_count_zero() {
    assert_eq!(natural_satellite_count(), 0);
}

#[test]
fn hill_sphere_positive() {
    assert!(hill_sphere_radius_m() > 0.0);
}

#[test]
fn hill_sphere_matches_constant() {
    let r = hill_sphere_radius_m();
    assert!((r - mercurys::HILL_SPHERE_RADIUS).abs() / r < 0.01);
}

#[test]
fn absence_reasons_non_empty() {
    let reasons = absence_reasons();
    assert!(!reasons.is_empty());
}

// ── MESSENGER ──

#[test]
fn messenger_orbit_params() {
    let m = messenger();
    assert!(m.periapsis_km > 0.0);
    assert!(m.apoapsis_km > m.periapsis_km);
}

#[test]
fn messenger_semi_major_axis_positive() {
    let m = messenger();
    assert!(m.semi_major_axis_m() > 0.0);
}

#[test]
fn messenger_orbital_period_positive() {
    let m = messenger();
    assert!(m.orbital_period_s() > 0.0);
}

#[test]
fn messenger_periapsis_radius() {
    let m = messenger();
    let pr = m.periapsis_radius_m();
    assert!(pr > mercurys::physics::orbit::MERCURY_RADIUS);
}

#[test]
fn messenger_velocity_at_periapsis() {
    let m = messenger();
    assert!(m.velocity_at_periapsis() > 0.0);
}

#[test]
fn messenger_velocity_at_apoapsis() {
    let m = messenger();
    assert!(m.velocity_at_apoapsis() > 0.0);
}

#[test]
fn messenger_faster_at_periapsis() {
    let m = messenger();
    assert!(m.velocity_at_periapsis() > m.velocity_at_apoapsis());
}

// ── BepiColombo MPO ──

#[test]
fn bepicolombo_mpo_orbit() {
    let m = bepicolombo_mpo();
    assert!(m.periapsis_km > 0.0);
    assert!(m.apoapsis_km > 0.0);
}

#[test]
fn mpo_semi_major_axis() {
    let m = bepicolombo_mpo();
    assert!(m.semi_major_axis_m() > 0.0);
}

#[test]
fn mpo_orbital_period() {
    let m = bepicolombo_mpo();
    assert!(m.orbital_period_s() > 0.0);
}

#[test]
fn mpo_periapsis_above_surface() {
    let m = bepicolombo_mpo();
    assert!(m.periapsis_radius_m() > mercurys::physics::orbit::MERCURY_RADIUS);
}

// ── BepiColombo MMO ──

#[test]
fn bepicolombo_mmo_orbit() {
    let m = bepicolombo_mmo();
    assert!(m.periapsis_km > 0.0);
    assert!(m.apoapsis_km > m.periapsis_km);
}

#[test]
fn mmo_semi_major_axis() {
    let m = bepicolombo_mmo();
    assert!(m.semi_major_axis_m() > 0.0);
}

#[test]
fn mmo_wider_orbit_than_mpo() {
    let mpo = bepicolombo_mpo();
    let mmo = bepicolombo_mmo();
    assert!(mmo.apoapsis_km > mpo.apoapsis_km);
}

// ── All Missions ──

#[test]
fn all_missions_non_empty() {
    let missions = all_missions();
    assert!(missions.len() >= 3);
}

#[test]
fn all_orbits_above_surface() {
    for sat in &all_missions() {
        assert!(
            sat.periapsis_radius_m() > mercurys::physics::orbit::MERCURY_RADIUS,
            "{}",
            sat.name
        );
    }
}

#[test]
fn all_periods_positive() {
    for sat in &all_missions() {
        assert!(sat.orbital_period_s() > 0.0, "{}", sat.name);
    }
}

#[test]
fn all_apoapsis_gt_periapsis() {
    for sat in &all_missions() {
        assert!(
            sat.apoapsis_radius_m() >= sat.periapsis_radius_m(),
            "{}",
            sat.name
        );
    }
}
