use super::vsop87::Vsop87Calculator;
use crate::astronomical::calendar::BsDate;
use crate::astronomical::core::{
JulianDay, newton_raphson::NewtonRaphsonSolver, time::get_ayanamsha,
};
#[derive(Debug, Clone, Copy)]
pub struct Sankranti {
pub zodiac_sign: u8, pub julian_day: JulianDay,
}
impl Sankranti {
pub fn sign_name(&self) -> &'static str {
match self.zodiac_sign {
0 => "Mesh",
1 => "Vrishabha",
2 => "Mithuna",
3 => "Karka",
4 => "Simha",
5 => "Kanya",
6 => "Tula",
7 => "Vrishchika",
8 => "Dhanu",
9 => "Makara",
10 => "Kumbha",
11 => "Meena",
_ => "Unknown",
}
}
pub fn to_bs_date(&self) -> BsDate {
BsDate::from_julian_day(self.julian_day).unwrap_or(BsDate {
year: 0,
month: 0,
day: 0,
})
}
}
pub struct SankrantiFinder;
impl SankrantiFinder {
pub fn find_sankranti(target_sign: u8, approx_jd: JulianDay) -> Result<Sankranti, String> {
let target_long = (target_sign as f64) * 30.0;
let f = |jd: f64| {
let julian_day = JulianDay(jd);
let sayana_long = Vsop87Calculator::sun_apparent_longitude(julian_day);
let ayanamsha = get_ayanamsha(julian_day);
let nirayana_long = (sayana_long - ayanamsha).rem_euclid(360.0);
let mut diff = nirayana_long - target_long;
diff = (diff + 180.0).rem_euclid(360.0) - 180.0;
diff
};
let solver = NewtonRaphsonSolver::new(50, 1e-8);
match solver.solve_numerical(f, approx_jd.0, 0.0001) {
Ok(root_jd) => Ok(Sankranti {
zodiac_sign: target_sign,
julian_day: JulianDay(root_jd),
}),
Err(e) => Err(format!("Sankranti calculation failed: {}", e)),
}
}
pub fn find_all_in_year(bs_year: i32) -> Result<Vec<Sankranti>, String> {
let mut results = Vec::new();
let approx_greg_year = bs_year - 57;
let mut current_search_jd = JulianDay::from_gregorian(approx_greg_year, 4, 1, 0.0);
for sign in 0..12 {
let sankranti = Self::find_sankranti(sign as u8, current_search_jd)?;
results.push(sankranti);
current_search_jd = JulianDay(sankranti.julian_day.0 + 25.0);
}
Ok(results)
}
}