use neptunes::biosphere::aerochemistry::*;
use neptunes::biosphere::ecosystems::*;
use neptunes::biosphere::fauna::*;

// ── Aerochemistry ────────────────────────────────────────────────────────

#[test]
fn hypothetical_chemotroph_name() {
    let c = hypotheticalchemotroph();
    assert!(!c.name.is_empty());
}

#[test]
fn hypothetical_chemotroph_zero_defaults() {
    let c = hypotheticalchemotroph();
    assert!((c.reactivesurfaream2).abs() < 1e-9);
    assert!((c.maxchemosynthesisumolm2s).abs() < 1e-9);
    assert!((c.suspensionaltitudem).abs() < 1e-9);
    assert!((c.metabolicreservoirkgm3).abs() < 1e-9);
}

#[test]
fn chemotroph_chemosynthesis_rate_finite() {
    let c = hypotheticalchemotroph();
    let rate = c.chemosynthesisrate(10.0, 5.0, 72.0);
    assert!(rate.is_finite());
}

#[test]
fn chemotroph_custom_chemosynthesis_rate() {
    let c = AerialChemotroph {
        name: "Active Chemotroph",
        reactivesurfaream2: 1e-6,
        maxchemosynthesisumolm2s: 100.0,
        suspensionaltitudem: 30000.0,
        metabolicreservoirkgm3: 0.01,
    };
    let rate = c.chemosynthesisrate(10.0, 5.0, 72.0);
    assert!(rate.is_finite());
}

#[test]
fn chemotroph_column_production() {
    let c = AerialChemotroph {
        name: "Active Chemotroph",
        reactivesurfaream2: 1e-6,
        maxchemosynthesisumolm2s: 100.0,
        suspensionaltitudem: 30000.0,
        metabolicreservoirkgm3: 0.01,
    };
    let rate = c.chemosynthesisrate(10.0, 5.0, 72.0);
    let cp = c.columnproduction(rate);
    assert!(cp.is_finite());
}

#[test]
fn chemotroph_volatile_flux() {
    let c = hypotheticalchemotroph();
    let vf = c.volatilefluxmmday(0.1, 1e-5);
    assert!(vf.is_finite());
}

#[test]
fn chemotroph_npp() {
    let c = hypotheticalchemotroph();
    let npp = c.nppkgcm2yr(1.0);
    assert!(npp.is_finite());
}

#[test]
fn chemotroph_reservoir_turnover() {
    let c = AerialChemotroph {
        name: "Active Chemotroph",
        reactivesurfaream2: 1e-6,
        maxchemosynthesisumolm2s: 100.0,
        suspensionaltitudem: 30000.0,
        metabolicreservoirkgm3: 0.01,
    };
    let npp = c.nppkgcm2yr(1.0);
    let rt = c.reservoirturnoveryr(npp);
    assert!(rt.is_finite());
}

#[test]
fn cloud_layer_chemosynthesis_efficiency() {
    let eff = cloudlayerchemosynthesisefficiency(1.0, 0.01);
    assert!(eff.is_finite());
    assert!(eff >= 0.0);
    assert!(eff <= 1.0);
}

#[test]
fn cloud_layer_chemosynthesis_high_optical_depth() {
    let low = cloudlayerchemosynthesisefficiency(5.0, 0.5);
    let high = cloudlayerchemosynthesisefficiency(1.0, 0.5);
    assert!(high > low);
}

// ── Ecosystems ───────────────────────────────────────────────────────────

#[test]
fn hypothetical_atmospheric_biome_name() {
    let eco = hypotheticalatmosphericbiome();
    assert!(!eco.name.is_empty());
}

#[test]
fn hypothetical_atmospheric_biome_zero_area() {
    let eco = hypotheticalatmosphericbiome();
    assert!((eco.areakm2).abs() < 1e-9);
}

#[test]
fn hypothetical_atmospheric_biome_empty_species() {
    let eco = hypotheticalatmosphericbiome();
    assert_eq!(eco.totalspecies(), 0);
    assert_eq!(eco.totalindividuals(), 0);
}

#[test]
fn hypothetical_atmospheric_biome_shannon_zero() {
    let eco = hypotheticalatmosphericbiome();
    let si = eco.shannonindex();
    assert!((si).abs() < 1e-9);
}

#[test]
fn hypothetical_atmospheric_biome_simpson_zero() {
    let eco = hypotheticalatmosphericbiome();
    let sd = eco.simpsondiversity();
    assert!(sd.is_finite());
}

#[test]
fn hypothetical_atmospheric_biome_energy() {
    let eco = hypotheticalatmosphericbiome();
    assert!(eco.energyinputwm2 > 0.0);
    assert!(eco.meantemperaturek > 0.0);
}

#[test]
fn ecosystem_custom_construct() {
    let eco = Ecosystem {
        name: "TestBiome",
        areakm2: 1e6,
        speciescounts: vec![100, 50, 20],
        netprimaryproductivitygcm2yr: 0.05,
        meantemperaturek: 72.0,
        energyinputwm2: 1.0,
    };
    assert_eq!(eco.totalspecies(), 3);
    assert_eq!(eco.totalindividuals(), 170);
}

#[test]
fn ecosystem_shannon_index_custom() {
    let eco = Ecosystem {
        name: "Rich",
        areakm2: 1e4,
        speciescounts: vec![100, 100, 100],
        netprimaryproductivitygcm2yr: 0.1,
        meantemperaturek: 72.0,
        energyinputwm2: 1.0,
    };
    let si = eco.shannonindex();
    assert!(si > 0.0);
}

#[test]
fn ecosystem_simpson_diversity_custom() {
    let eco = Ecosystem {
        name: "Rich",
        areakm2: 1e4,
        speciescounts: vec![100, 100, 100],
        netprimaryproductivitygcm2yr: 0.1,
        meantemperaturek: 72.0,
        energyinputwm2: 1.0,
    };
    let sd = eco.simpsondiversity();
    assert!(sd > 0.0);
    assert!(sd <= 1.0);
}

#[test]
fn ecosystem_expected_species_from_area() {
    let eco = Ecosystem {
        name: "Test",
        areakm2: 1e6,
        speciescounts: vec![50],
        netprimaryproductivitygcm2yr: 0.05,
        meantemperaturek: 72.0,
        energyinputwm2: 1.0,
    };
    let es = eco.expectedspeciesfromarea(0.25, 10.0);
    assert!(es.is_finite());
    assert!(es > 0.0);
}

#[test]
fn ecosystem_total_npp() {
    let eco = Ecosystem {
        name: "NPP",
        areakm2: 1000.0,
        speciescounts: vec![10],
        netprimaryproductivitygcm2yr: 0.05,
        meantemperaturek: 72.0,
        energyinputwm2: 1.0,
    };
    let tnpp = eco.totalnppgcyr();
    assert!(tnpp > 0.0);
}

#[test]
fn ecosystem_biomass_turnover_infinite_when_no_npp() {
    let eco = hypotheticalatmosphericbiome();
    let bt = eco.biomassturnovertimeyr(0.01);
    assert!(bt.is_infinite());
}

#[test]
fn ecosystem_biomass_turnover_custom() {
    let eco = Ecosystem {
        name: "BT",
        areakm2: 1e4,
        speciescounts: vec![100],
        netprimaryproductivitygcm2yr: 0.1,
        meantemperaturek: 72.0,
        energyinputwm2: 1.0,
    };
    let bt = eco.biomassturnovertimeyr(0.5);
    assert!(bt > 0.0);
    assert!(bt.is_finite());
}

// ── Fauna ────────────────────────────────────────────────────────────────

#[test]
fn h2_floater_name() {
    let f = hypotheticalh2floater();
    assert!(!f.speciesname.is_empty());
}

#[test]
fn h2_floater_zero_defaults() {
    let f = hypotheticalh2floater();
    assert!((f.count).abs() < 1e-9);
    assert!((f.carryingcapacity).abs() < 1e-9);
    assert!((f.intrinsicgrowthrate).abs() < 1e-9);
}

#[test]
fn h2_floater_effective_mass() {
    let f = hypotheticalh2floater();
    assert!((f.effectivemasskg - 1.0).abs() < 1e-9);
}

#[test]
fn h2_floater_growth_rate_zero() {
    let f = hypotheticalh2floater();
    let gr = f.growthrate();
    assert!(gr.is_finite());
}

#[test]
fn h2_floater_project_forward_zero_pop() {
    let f = hypotheticalh2floater();
    let pop = f.projectforward(1.0);
    assert!((pop).abs() < 1e-9);
}

#[test]
fn h2_floater_metabolic_rate() {
    let f = hypotheticalh2floater();
    let mr = f.metabolicratew();
    assert!(mr.is_finite());
}

#[test]
fn h2_floater_doubling_time_infinite() {
    let f = hypotheticalh2floater();
    let dt = f.doublingtimeyr();
    assert!(dt.is_infinite());
}

#[test]
fn custom_aeroplankton_project_forward() {
    let a = Aeroplankton {
        speciesname: "Custom",
        count: 100.0,
        carryingcapacity: 1000.0,
        intrinsicgrowthrate: 0.5,
        effectivemasskg: 1e-6,
    };
    let pop = a.projectforward(1.0);
    assert!(pop > 100.0);
    assert!(pop < 1000.0);
}

#[test]
fn custom_aeroplankton_doubling_time() {
    let a = Aeroplankton {
        speciesname: "Custom",
        count: 100.0,
        carryingcapacity: 1000.0,
        intrinsicgrowthrate: 0.5,
        effectivemasskg: 1e-6,
    };
    let dt = a.doublingtimeyr();
    assert!(dt > 0.0);
    assert!(dt.is_finite());
}

#[test]
fn aeroplankton_drag_coefficient_low_re() {
    let cd = Aeroplankton::dragcoefficient(0.5);
    assert!(cd > 24.0);
}

#[test]
fn aeroplankton_drag_coefficient_high_re() {
    let cd = Aeroplankton::dragcoefficient(500.0);
    assert!(cd > 0.0);
    assert!(cd < 24.0);
}

#[test]
fn h2_floater_terminal_velocity() {
    let f = hypotheticalh2floater();
    let tv = f.terminalvelocityms(1e-4, 0.45);
    assert!(tv.is_finite());
}

#[test]
fn chemoautotroph_name() {
    let ca = hypotheticalchemoautotroph();
    assert!(!ca.speciesname.is_empty());
}

#[test]
fn chemoautotroph_tiny_mass() {
    let ca = hypotheticalchemoautotroph();
    assert!(ca.effectivemasskg < 1e-6);
    assert!(ca.effectivemasskg > 0.0);
}

#[test]
fn cloud_layer_interaction_producer_growth() {
    let p = Aeroplankton {
        speciesname: "Prod",
        count: 500.0,
        carryingcapacity: 1000.0,
        intrinsicgrowthrate: 0.3,
        effectivemasskg: 1e-6,
    };
    let c = Aeroplankton {
        speciesname: "Cons",
        count: 50.0,
        carryingcapacity: 200.0,
        intrinsicgrowthrate: 0.1,
        effectivemasskg: 1e-5,
    };
    let cli = CloudLayerInteraction {
        producers: p,
        consumers: c,
        interactionrate: 0.01,
        conversionefficiency: 0.3,
        consumerlossrate: 0.05,
    };
    let pg = cli.producergrowthrate();
    assert!(pg.is_finite());
}

#[test]
fn cloud_layer_interaction_consumer_growth() {
    let p = Aeroplankton {
        speciesname: "Prod",
        count: 500.0,
        carryingcapacity: 1000.0,
        intrinsicgrowthrate: 0.3,
        effectivemasskg: 1e-6,
    };
    let c = Aeroplankton {
        speciesname: "Cons",
        count: 50.0,
        carryingcapacity: 200.0,
        intrinsicgrowthrate: 0.1,
        effectivemasskg: 1e-5,
    };
    let cli = CloudLayerInteraction {
        producers: p,
        consumers: c,
        interactionrate: 0.01,
        conversionefficiency: 0.3,
        consumerlossrate: 0.05,
    };
    let cg = cli.consumergrowthrate();
    assert!(cg.is_finite());
}

#[test]
fn cloud_layer_interaction_step() {
    let p = Aeroplankton {
        speciesname: "Prod",
        count: 500.0,
        carryingcapacity: 1000.0,
        intrinsicgrowthrate: 0.3,
        effectivemasskg: 1e-6,
    };
    let c = Aeroplankton {
        speciesname: "Cons",
        count: 50.0,
        carryingcapacity: 200.0,
        intrinsicgrowthrate: 0.1,
        effectivemasskg: 1e-5,
    };
    let mut cli = CloudLayerInteraction {
        producers: p,
        consumers: c,
        interactionrate: 0.01,
        conversionefficiency: 0.3,
        consumerlossrate: 0.05,
    };
    cli.step(0.1);
    assert!(cli.producers.count.is_finite());
    assert!(cli.consumers.count.is_finite());
}
