use crate::config::parameters::*;

#[derive(Clone, Copy, Debug)]
pub enum TrojanPoint {
    L4,
    L5,
}

pub struct Trojan {
    pub radius: f64,
    pub density: f64,
    pub mass: f64,
    pub host_semi_major_au: f64,
    pub libration_amplitude: f64,
    pub lagrange_point: TrojanPoint,
    pub albedo: f64,
    pub eccentricity: f64,
    pub inclination: f64,
}

impl Trojan {
    pub fn new(radius_m: f64, density: f64, host_semi_major_au: f64) -> Self {
        let radius = radius_m.clamp(MIN_ASTEROID_RADIUS, MAX_ASTEROID_RADIUS);
        let density = density.clamp(500.0, 8000.0);
        let mass = sphere_mass(radius, density);

        Self {
            radius,
            density,
            mass,
            host_semi_major_au,
            libration_amplitude: 0.2,
            lagrange_point: TrojanPoint::L4,
            albedo: 0.06,
            eccentricity: 0.05,
            inclination: 0.0,
        }
    }

    pub fn with_lagrange_point(mut self, lp: TrojanPoint) -> Self {
        self.lagrange_point = lp;
        self
    }

    pub fn with_libration_amplitude(mut self, amp_rad: f64) -> Self {
        self.libration_amplitude = amp_rad.clamp(0.01, 1.0);
        self
    }

    pub fn with_eccentricity(mut self, e: f64) -> Self {
        self.eccentricity = e.clamp(0.0, 0.3);
        self
    }

    pub fn with_inclination(mut self, inc_deg: f64) -> Self {
        self.inclination = inc_deg.to_radians();
        self
    }

    pub fn orbital_period(&self) -> f64 {
        orbital_period(self.host_semi_major_au, SOLAR_MASS)
    }

    pub fn orbital_period_years(&self) -> f64 {
        self.orbital_period() / YEAR
    }

    pub fn surface_gravity(&self) -> f64 {
        surface_gravity(self.mass, self.radius)
    }

    pub fn escape_velocity(&self) -> f64 {
        escape_velocity(self.mass, self.radius)
    }

    pub fn libration_period(&self) -> f64 {
        let t_orb = self.orbital_period();
        t_orb / (27.0_f64.sqrt() / (4.0 * std::f64::consts::PI))
    }

    pub fn lagrange_angle(&self) -> f64 {
        match self.lagrange_point {
            TrojanPoint::L4 => std::f64::consts::PI / 3.0,
            TrojanPoint::L5 => -std::f64::consts::PI / 3.0,
        }
    }

    pub fn lagrange_name(&self) -> &'static str {
        match self.lagrange_point {
            TrojanPoint::L4 => "L4 (leading)",
            TrojanPoint::L5 => "L5 (trailing)",
        }
    }

    pub fn stability_parameter(&self, host_mass: f64) -> f64 {
        self.mass / (host_mass + self.mass)
    }

    pub fn equilibrium_temperature(&self) -> f64 {
        equilibrium_temperature(SOLAR_LUMINOSITY, self.host_semi_major_au * AU, self.albedo)
    }
}
