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

pub struct RubblePile {
    pub effective_radius: f64,
    pub bulk_density: f64,
    pub mass: f64,
    pub porosity: f64,
    pub grain_density: f64,
    pub semi_major_axis: f64,
    pub eccentricity: f64,
    pub rotation_period: f64,
    pub albedo: f64,
    pub axis_ratios: (f64, f64),
}

impl RubblePile {
    pub fn new(effective_radius_m: f64, grain_density: f64, porosity: f64) -> Self {
        let radius = effective_radius_m.clamp(MIN_ASTEROID_RADIUS, MAX_ASTEROID_RADIUS);
        let porosity = porosity.clamp(0.0, 0.8);
        let grain_density = grain_density.clamp(1000.0, 8000.0);
        let bulk_density = grain_density * (1.0 - porosity);
        let mass = sphere_mass(radius, bulk_density);

        Self {
            effective_radius: radius,
            bulk_density,
            mass,
            porosity,
            grain_density,
            semi_major_axis: 2.5,
            eccentricity: 0.1,
            rotation_period: 6.0 * 3600.0,
            albedo: 0.10,
            axis_ratios: (1.0, 0.8),
        }
    }

    pub fn with_orbit(mut self, semi_major_au: f64, ecc: f64) -> Self {
        self.semi_major_axis = semi_major_au.max(0.1);
        self.eccentricity = ecc.clamp(0.0, 0.999);
        self
    }

    pub fn with_rotation_period(mut self, hours: f64) -> Self {
        self.rotation_period = hours.max(0.5) * 3600.0;
        self
    }

    pub fn with_axis_ratios(mut self, b_over_a: f64, c_over_a: f64) -> Self {
        self.axis_ratios = (b_over_a.clamp(0.1, 1.0), c_over_a.clamp(0.1, 1.0));
        self
    }

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

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

    pub fn spin_limit_period(&self) -> f64 {
        (3.0 * std::f64::consts::PI / (G * self.bulk_density)).sqrt()
    }

    pub fn is_spin_stable(&self) -> bool {
        self.rotation_period > self.spin_limit_period()
    }

    pub fn cohesionless_strength(&self) -> f64 {
        0.0
    }

    pub fn yorp_timescale(&self, distance_au: f64) -> f64 {
        let r_km = self.effective_radius / 1000.0;
        1e6 * YEAR * (r_km / 1.0).powi(2) * (distance_au / 2.5).powi(2)
    }

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

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

    pub fn volume_equivalent_sphere(&self) -> f64 {
        sphere_volume(self.effective_radius)
    }

    pub fn macro_porosity_estimate(&self) -> f64 {
        self.porosity * 0.6
    }

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