use crate::SIDEREAL_DAY_S;
use crate::SOLAR_DAY_S;

pub struct DayNightCycle {
    pub solar_day_s: f64,
    pub sidereal_day_s: f64,
}

impl Default for DayNightCycle {
    fn default() -> Self {
        Self::new()
    }
}

impl DayNightCycle {
    pub fn new() -> Self {
        Self {
            solar_day_s: SOLAR_DAY_S,
            sidereal_day_s: SIDEREAL_DAY_S,
        }
    }

    pub fn solar_day_fraction(&self, elapsed_s: f64) -> f64 {
        (elapsed_s % self.solar_day_s) / self.solar_day_s
    }

    pub fn is_daytime(&self, surface_lon_deg: f64, subsolar_lon_deg: f64) -> bool {
        let mut diff = (surface_lon_deg - subsolar_lon_deg).abs() % 360.0;
        if diff > 180.0 {
            diff = 360.0 - diff;
        }
        diff < 90.0
    }

    pub fn daylight_hours(&self, lat_deg: f64) -> f64 {
        if lat_deg.is_finite() {
            self.solar_day_s / 3600.0 / 2.0
        } else {
            f64::NAN
        }
    }

    pub fn sidereal_angle(&self, elapsed_s: f64) -> f64 {
        2.0 * std::f64::consts::PI * (elapsed_s / self.sidereal_day_s)
    }

    pub fn solar_hour_angle(&self, elapsed_s: f64) -> f64 {
        2.0 * std::f64::consts::PI * (elapsed_s / self.solar_day_s)
    }
}

pub fn twilight_duration_s() -> f64 {
    0.0
}

pub fn sun_angular_diameter_rad(distance_au: f64) -> f64 {
    let sun_radius_m = 6.9634e8;
    let distance_m = distance_au * 1.496e11;
    2.0 * (sun_radius_m / distance_m).atan()
}
