use sciforge::hub::domain::astronomy::orbits::escape_velocity;
use sciforge::hub::domain::common::constants::G;

pub struct Impactor {
    pub masskg: f64,
    pub velocityms: f64,
    pub densitykgm3: f64,
    pub angledeg: f64,
}

impl Impactor {
    pub fn asteroid(diameterm: f64, velocitykms: f64) -> Self {
        let density = crate::STONYASTEROIDDENSITY;
        let radius = diameterm / 2.0;
        let volume = (4.0 / 3.0) * std::f64::consts::PI * radius.powi(3);
        Self {
            masskg: density * volume,
            velocityms: velocitykms * 1000.0,
            densitykgm3: density,
            angledeg: 45.0,
        }
    }

    pub fn kineticenergyj(&self) -> f64 {
        0.5 * self.masskg * self.velocityms.powi(2)
    }

    pub fn kineticenergymt(&self) -> f64 {
        self.kineticenergyj() / crate::MTTNTTOJOULE
    }

    pub fn impactvelocity(&self) -> f64 {
        let vesc = escape_velocity(G * crate::NEPTUNEMASS, crate::NEPTUNEEQUATORIALRADIUS);
        (self.velocityms.powi(2) + vesc.powi(2)).sqrt()
    }

    pub fn craterdiameterm(&self, targetdensity: f64) -> f64 {
        let g = *crate::SURFACEGRAVITY;
        let anglerad = self.angledeg.to_radians();
        let dprojectile = (6.0 * self.masskg / (std::f64::consts::PI * self.densitykgm3)).cbrt();
        1.161
            * (self.densitykgm3 / targetdensity).powf(1.0 / 3.0)
            * dprojectile.powf(0.78)
            * self.velocityms.powf(0.44)
            * g.powf(-0.22)
            * anglerad.sin().powf(1.0 / 3.0)
    }

    pub fn fireballradiusm(&self) -> f64 {
        let energykt = self.kineticenergyj() / crate::KTTNTTOJOULE;
        55.0 * energykt.powf(0.4)
    }

    pub fn ejectavolumem3(&self, targetdensity: f64) -> f64 {
        let craterd = self.craterdiameterm(targetdensity);
        let craterdepth = craterd / 5.0;
        std::f64::consts::PI / 6.0 * craterd * craterd * craterdepth
    }
}

pub fn cometimpact() -> Impactor {
    Impactor::asteroid(5000.0, 25.0)
}

pub fn kuiperbeltimpactor() -> Impactor {
    Impactor::asteroid(100.0, 20.0)
}
