use mercurys::temporal::calendar::{MercuryCalendar, orbital_period_days, solar_day_earth_days};
use mercurys::temporal::epoch::{
    J2000_JD, MERCURY_PERIHELION_J2000_JD, gmst_hours, julian_centuries, mean_anomaly_deg,
    mean_longitude_deg, sim_seconds_to_jd,
};
use mercurys::temporal::time_scale::TimeScale;

// ── Calendar ──

#[test]
fn orbital_period_about_88() {
    let d = orbital_period_days();
    assert!((d - 87.969).abs() < 1.0);
}

#[test]
fn solar_day_about_176() {
    let d = solar_day_earth_days();
    assert!((d - 175.94).abs() < 2.0);
}

#[test]
fn calendar_new() {
    let c = MercuryCalendar::new(0.0);
    assert_eq!(c.elapsed_s, 0.0);
}

#[test]
fn mercury_years_from_elapsed() {
    let one_year_s = 87.969 * 86_400.0;
    let c = MercuryCalendar::new(one_year_s);
    assert!((c.mercury_years() - 1.0).abs() < 0.05);
}

#[test]
fn mercury_solar_days_from_elapsed() {
    let one_sd_s = mercurys::SOLAR_DAY_S;
    let c = MercuryCalendar::new(one_sd_s);
    assert!((c.mercury_solar_days() - 1.0).abs() < 0.05);
}

#[test]
fn earth_days_from_elapsed() {
    let c = MercuryCalendar::new(86_400.0);
    assert!((c.earth_days() - 1.0).abs() < 0.001);
}

#[test]
fn year_fraction_wraps() {
    let half_year = 87.969 * 86_400.0 / 2.0;
    let c = MercuryCalendar::new(half_year);
    let f = c.year_fraction();
    assert!(f > 0.4 && f < 0.6);
}

#[test]
fn mean_anomaly_from_calendar() {
    let c = MercuryCalendar::new(87.969 * 86_400.0);
    let ma = c.mean_anomaly_rad();
    assert!(ma.is_finite() && ma >= 0.0);
}

// ── Epoch ──

#[test]
fn j2000_constants() {
    assert_eq!(J2000_JD, 2_451_545.0);
}

#[test]
fn perihelion_j2000_after_j2000() {
    assert_eq!(MERCURY_PERIHELION_J2000_JD, 2_451_590.257);
}

#[test]
fn julian_centuries_at_j2000() {
    let t = julian_centuries(J2000_JD);
    assert!(t.abs() < 0.001);
}

#[test]
fn julian_centuries_one_century() {
    let t = julian_centuries(J2000_JD + 36525.0);
    assert!((t - 1.0).abs() < 0.001);
}

#[test]
fn mean_longitude_finite() {
    let l = mean_longitude_deg(0.0);
    assert!(l.is_finite());
}

#[test]
fn mean_anomaly_finite() {
    let m = mean_anomaly_deg(0.0);
    assert!(m.is_finite());
}

#[test]
fn sim_to_jd_advances() {
    let jd = sim_seconds_to_jd(J2000_JD, 86_400.0);
    assert!(jd > J2000_JD);
}

#[test]
fn sim_to_jd_one_day() {
    let jd = sim_seconds_to_jd(J2000_JD, 86_400.0);
    assert!((jd - J2000_JD - 1.0).abs() < 0.001);
}

#[test]
fn gmst_hours_at_j2000() {
    let g = gmst_hours(J2000_JD);
    assert!(g.is_finite() && (0.0..24.0).contains(&g));
}

// ── Time Scale ──

#[test]
fn realtime_factor_1() {
    let ts = TimeScale::realtime();
    assert!((ts.apply(1.0) - 1.0).abs() < 0.001);
}

#[test]
fn solar_day_per_second_fast() {
    let ts = TimeScale::solar_day_per_second();
    let sim = ts.apply(1.0);
    assert!(sim > 1_000_000.0);
}

#[test]
fn year_per_second_faster() {
    let ts = TimeScale::year_per_second();
    let sim = ts.apply(1.0);
    assert!(sim > 7_000_000.0);
}

#[test]
fn custom_factor() {
    let ts = TimeScale::new(100.0);
    assert!((ts.apply(1.0) - 100.0).abs() < 0.001);
}

#[test]
fn set_factor_changes() {
    let mut ts = TimeScale::new(1.0);
    ts.set_factor(50.0);
    assert!((ts.apply(1.0) - 50.0).abs() < 0.001);
}

#[test]
fn pause_stops_time() {
    let mut ts = TimeScale::new(10.0);
    ts.pause();
    assert!(ts.is_paused());
    assert_eq!(ts.apply(1.0), 0.0);
}
