use super::orbit::{ECCENTRICITY, MERCURY_MASS, MERCURY_RADIUS, SEMI_MAJOR_AXIS};
use sciforge::hub::domain::astronomy::celestial::{gravitational_force, tidal_force};
use sciforge::hub::domain::common::constants::{G, SOLAR_MASS};

pub struct SolarTide {
    pub distance_m: f64,
}

impl SolarTide {
    pub fn at_mean_distance() -> Self {
        Self {
            distance_m: SEMI_MAJOR_AXIS,
        }
    }

    pub fn at_perihelion() -> Self {
        Self {
            distance_m: SEMI_MAJOR_AXIS * (1.0 - ECCENTRICITY),
        }
    }

    pub fn at_aphelion() -> Self {
        Self {
            distance_m: SEMI_MAJOR_AXIS * (1.0 + ECCENTRICITY),
        }
    }

    pub fn at_distance(distance_m: f64) -> Self {
        Self { distance_m }
    }

    pub fn tidal_acceleration(&self) -> f64 {
        tidal_force(SOLAR_MASS, self.distance_m, MERCURY_RADIUS)
    }

    pub fn tidal_potential(&self, theta: f64) -> f64 {
        let r = MERCURY_RADIUS;
        let d = self.distance_m;
        let base = -G * SOLAR_MASS * r * r / (d * d * d) * (1.5 * theta.cos().powi(2) - 0.5);
        (1.0 + crate::LOVE_K2) * base
    }

    pub fn tidal_bulge_height(&self) -> f64 {
        let g_surface = G * MERCURY_MASS / (MERCURY_RADIUS * MERCURY_RADIUS);
        crate::LOVE_H2 * self.tidal_acceleration() * MERCURY_RADIUS / g_surface
    }

    pub fn gravitational_attraction(&self) -> f64 {
        gravitational_force(SOLAR_MASS, MERCURY_MASS, self.distance_m)
    }
}

pub fn spin_orbit_resonance() -> (u32, u32) {
    (3, 2)
}

pub fn tidal_dissipation_rate(distance_m: f64) -> f64 {
    let n = 2.0 * std::f64::consts::PI / crate::ORBITAL_PERIOD_S;
    let q = crate::TIDAL_Q;
    let k2 = crate::LOVE_K2;
    let r5 = MERCURY_RADIUS.powi(5);
    let d3 = distance_m.powi(3);
    (21.0 / 2.0) * k2 * n * G * SOLAR_MASS * SOLAR_MASS * r5 / (q * d3 * d3)
}

pub fn bulge_variation() -> (f64, f64) {
    let peri = SolarTide::at_perihelion().tidal_bulge_height();
    let aph = SolarTide::at_aphelion().tidal_bulge_height();
    (peri, aph)
}

pub fn tidal_locking_timescale(rigidity_pa: f64) -> f64 {
    let omega = crate::ANGULAR_VELOCITY;
    let q = crate::TIDAL_Q;
    let a6 = SEMI_MAJOR_AXIS.powi(6);
    let r5 = MERCURY_RADIUS.powi(5);
    (omega * a6 * rigidity_pa * q) / (6.0 * G * SOLAR_MASS.powi(2) * r5)
}

pub fn perihelion_aphelion_tide_ratio() -> f64 {
    let peri = SolarTide::at_perihelion().tidal_acceleration();
    let aph = SolarTide::at_aphelion().tidal_acceleration();
    peri / aph
}
