use neptunes::geodata::bathymetry::*;
use neptunes::geodata::coordinates::*;
use neptunes::geodata::elevation::*;
use neptunes::geodata::regions::*;

// ── Bathymetry (Interior Layers) ─────────────────────────────────────────

#[test]
fn interior_layer_data_global() {
    let data = InteriorLayerData::global(60.0);
    assert!(data.resolutionarcsec > 0.0);
    assert!(data.rows > 0);
    assert!(data.cols > 0);
}

#[test]
fn interior_layer_data_sample() {
    let data = InteriorLayerData::global(60.0);
    let val = data.sample(0.0, 0.0);
    assert!(val.is_finite());
}

#[test]
fn interior_layer_data_is_ice_mantle_consistent() {
    let data = InteriorLayerData::global(60.0);
    let val = data.sample(45.0, 90.0);
    let is_mantle = data.isicemantle(45.0, 90.0);
    assert_eq!(is_mantle, val < -7000.0);
}

#[test]
fn interior_stats_valid() {
    let stats = InteriorLayerData::interiorstats();
    assert!(stats.totalradiuskm > 0.0);
    assert!(stats.coreradiuskm > 0.0);
    assert!(stats.icemantledepthkm > 0.0);
    assert!(stats.atmospheredepthkm > 0.0);
}

#[test]
fn interior_stats_radius_sum() {
    let stats = InteriorLayerData::interiorstats();
    assert!(stats.totalradiuskm > stats.coreradiuskm);
}

#[test]
fn interior_major_layers_nonempty() {
    let layers = InteriorLayer::majorlayers();
    assert!(!layers.is_empty());
}

#[test]
fn interior_major_layers_boundaries() {
    let layers = InteriorLayer::majorlayers();
    for layer in &layers {
        assert!(!layer.name.is_empty());
        assert!(layer.outerboundarykm >= layer.innerboundarykm);
        assert!(layer.avgdensitykgm3 > 0.0);
    }
}

// ── Coordinates ──────────────────────────────────────────────────────────

#[test]
fn latlon_to_ecef_and_back() {
    let ll = LatLon::new(45.0, 90.0, 0.0);
    let ecef = ll.toecef();
    assert!(ecef.x.is_finite());
    assert!(ecef.y.is_finite());
    assert!(ecef.z.is_finite());
}

#[test]
fn latlon_equator() {
    let ll = LatLon::new(0.0, 0.0, 0.0);
    let ecef = ll.toecef();
    assert!(ecef.x > 0.0);
    assert!(ecef.y.abs() < 1e-3);
}

#[test]
fn latlon_pole() {
    let ll = LatLon::new(90.0, 0.0, 0.0);
    let ecef = ll.toecef();
    assert!(ecef.z.abs() > 0.0);
}

#[test]
fn ecef_radius_near_neptune() {
    let ll = LatLon::new(0.0, 0.0, 0.0);
    let ecef = ll.toecef();
    let r = (ecef.x * ecef.x + ecef.y * ecef.y + ecef.z * ecef.z).sqrt();
    assert!(r > 24000000.0);
}

#[test]
fn ecef_roundtrip() {
    let ll1 = LatLon::new(30.0, 60.0, 0.0);
    let ecef = ll1.toecef();
    let ll2 = ecef.tolatlon();
    assert!((ll1.latdeg - ll2.latdeg).abs() < 0.1);
    assert!((ll1.londeg - ll2.londeg).abs() < 0.1);
}

#[test]
fn latlon_to_cartesian_simple() {
    let ll = LatLon::new(0.0, 0.0, 0.0);
    let xyz = ll.tocartesiansimple();
    assert!(xyz[0].is_finite());
    assert!(xyz[1].is_finite());
    assert!(xyz[2].is_finite());
}

#[test]
fn latlon_distance_same_point() {
    let ll = LatLon::new(10.0, 20.0, 0.0);
    let d = ll.distanceto(&ll);
    assert!(d < 1.0);
}

#[test]
fn latlon_distance_different_points() {
    let a = LatLon::new(0.0, 0.0, 0.0);
    let b = LatLon::new(10.0, 10.0, 0.0);
    let d = a.distanceto(&b);
    assert!(d > 0.0);
}

// ── Elevation ────────────────────────────────────────────────────────────

#[test]
fn elevation_provider_global() {
    let ep = ElevationProvider::global(60.0);
    assert!(ep.resolutionarcsec > 0.0);
    assert!(ep.rows > 0);
    assert!(ep.cols > 0);
}

#[test]
fn elevation_provider_sample() {
    let ep = ElevationProvider::global(60.0);
    let elev = ep.sample(0.0, 0.0);
    assert!(elev.is_finite());
}

#[test]
fn elevation_provider_various_positions() {
    let ep = ElevationProvider::global(60.0);
    for lat in [-90.0, -45.0, 0.0, 45.0, 90.0] {
        for lon in [-180.0, 0.0, 180.0] {
            let e = ep.sample(lat, lon);
            assert!(e.is_finite());
        }
    }
}

#[test]
fn notable_features_nonempty() {
    let features = ElevationProvider::notablefeatures();
    assert!(!features.is_empty());
    for (name, lat, lon, elev) in &features {
        assert!(!name.is_empty());
        assert!(lat.is_finite());
        assert!(lon.is_finite());
        assert!(elev.is_finite());
    }
}

// ── Regions ──────────────────────────────────────────────────────────────

#[test]
fn region_type_atmospheric_band() {
    let rt = RegionType::AtmosphericBand;
    assert_eq!(rt, RegionType::AtmosphericBand);
}

#[test]
fn region_type_all_variants() {
    let variants = [
        RegionType::AtmosphericBand,
        RegionType::VortexRegion,
        RegionType::PolarCap,
        RegionType::StormSystem,
        RegionType::CloudFeature,
    ];
    assert_eq!(variants.len(), 5);
}

#[test]
fn region_database_atmospheric_bands() {
    let db = RegionDatabase::atmosphericbands();
    assert!(!db.regions.is_empty());
}

#[test]
fn region_database_regions_valid() {
    let db = RegionDatabase::atmosphericbands();
    for r in &db.regions {
        assert!(!r.name.is_empty());
        assert!(r.areakm2 > 0.0);
    }
}

#[test]
fn region_database_boundaries() {
    let db = RegionDatabase::atmosphericbands();
    for r in &db.regions {
        assert!(!r.boundary.is_empty());
    }
}
