use serde::{Serialize, Deserialize};
use wasm_bindgen::prelude::*;
use alloc::vec::Vec;
use alloc::vec;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlanetInput {
pub id: i32,
pub longitude: f64,
pub speed: f64,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[wasm_bindgen]
pub struct ShadbalaResult {
pub total_rupas: f64,
pub ishta_phala: f64,
pub kashta_phala: f64,
pub sthana_bala: f64,
pub dig_bala: f64,
pub kala_bala: f64,
pub chesta_bala: f64,
pub naisargika_bala: f64,
pub drik_bala: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[wasm_bindgen]
pub struct ShadbalaProfile {
pub sun: ShadbalaResult,
pub moon: ShadbalaResult,
pub mars: ShadbalaResult,
pub mercury: ShadbalaResult,
pub jupiter: ShadbalaResult,
pub venus: ShadbalaResult,
pub saturn: ShadbalaResult,
}
fn exaltation_point(planet_id: i32) -> f64 {
match planet_id {
0 => 10.0, 1 => 33.0, 2 => 298.0, 3 => 165.0, 4 => 95.0, 5 => 357.0, 6 => 200.0, _ => 0.0,
}
}
fn calculate_uchcha_bala(long: f64, planet_id: i32) -> f64 {
let deep_exalt = exaltation_point(planet_id);
let deep_deb = (deep_exalt + 180.0) % 360.0;
let mut arc = (long - deep_deb).rem_euclid(360.0);
if arc > 180.0 {
arc = 360.0 - arc;
}
arc / 3.0
}
fn calculate_saptavargaja_bala(
planet_id: i32,
planets: &[PlanetInput],
) -> f64 {
use crate::vedic::vargas::{calculate_varga_position, VargaType, VargaConfig};
use crate::vedic::dignity::{calculate_dignity, get_panchadha_relationship, Dignity};
let mut total_bala = 0.0;
let target_long = planets.iter().find(|p| p.id == planet_id).map(|p| p.longitude).unwrap_or(0.0);
let target_sign = ((target_long / 30.0).floor() as u8 % 12) + 1;
let vargas = [
VargaType::D1, VargaType::D2, VargaType::D3,
VargaType::D7, VargaType::D9, VargaType::D12, VargaType::D30,
];
let config = VargaConfig::new();
for varga_type in vargas.iter() {
let v_pos = calculate_varga_position(target_long, *varga_type, &config);
let v_sign = v_pos.sign;
let lord_id = match v_sign {
1 | 8 => 2, 2 | 7 => 5, 3 | 6 => 3, 4 => 1, 5 => 0, 9 | 12 => 4, 10 | 11 => 6, _ => -1,
};
let lord_data = planets.iter().find(|p| p.id == lord_id);
let lord_sign_d1 = lord_data.map(|p| ((p.longitude / 30.0).floor() as u8 % 12) + 1).unwrap_or(0);
let p_name = match planet_id {
0 => "Sun",
1 => "Moon",
2 => "Mars",
3 => "Mercury",
4 => "Jupiter",
5 => "Venus",
6 => "Saturn",
_ => "Sun",
};
let dig_status = calculate_dignity(p_name, v_pos.full_longitude);
let strength = if dig_status == Dignity::Moolatrikona {
45.0
} else if dig_status == Dignity::OwnSign {
30.0
} else if planet_id == lord_id {
30.0
} else {
let dignity = get_panchadha_relationship(planet_id, target_sign, lord_id, lord_sign_d1);
match dignity {
Dignity::GreatFriend => 22.5,
Dignity::Friend => 15.0,
Dignity::Neutral => 7.5,
Dignity::Enemy => 3.75,
Dignity::GreatEnemy => 1.875,
_ => 15.0, }
};
total_bala += strength;
}
total_bala
}
fn calculate_sthana_bala(planet_id: i32, planets: &[PlanetInput], jd: f64) -> f64 {
let long = planets.iter().find(|p| p.id == planet_id).map(|p| p.longitude).unwrap_or(0.0);
let uchcha = calculate_uchcha_bala(long, planet_id);
let saptavargaja = calculate_saptavargaja_bala(planet_id, planets);
uchcha + saptavargaja
}
fn calculate_dig_bala(long: f64, planet_id: i32, ascendant: f64) -> f64 {
let power_point = match planet_id {
0 | 2 => (ascendant + 270.0) % 360.0, 1 | 5 => (ascendant + 90.0) % 360.0, 3 | 4 => ascendant, 6 => (ascendant + 180.0) % 360.0, _ => 0.0,
};
let mut arc = (long - power_point).rem_euclid(360.0);
if arc > 180.0 {
arc = 360.0 - arc;
}
(180.0 - arc) / 3.0
}
fn calculate_chesta_bala(planet_id: i32, speed: f64) -> f64 {
let avg_speed = match planet_id {
0 => 0.98,
1 => 13.17,
2 => 0.52,
3 => 1.38, 4 => 0.08,
5 => 1.20, 6 => 0.03,
_ => 1.0,
};
if speed < 0.0 {
return 60.0; }
if speed.abs() < (0.1 * avg_speed) {
return 15.0; }
if speed > 1.2 * avg_speed {
return 45.0; }
if speed < 0.5 * avg_speed {
return 15.0; }
30.0 }
fn calculate_aspect_value(aspect_angle: f64, aspector_id: i32) -> f64 {
let d = aspect_angle;
let mut val = 0.0;
if d > 30.0 && d <= 60.0 {
val = (d - 30.0) / 2.0;
} else if d > 60.0 && d <= 90.0 {
val = (d - 60.0) + 15.0;
} else if d > 90.0 && d <= 120.0 {
val = 45.0 - (d - 90.0) / 2.0;
} else if d > 120.0 && d <= 150.0 {
val = 30.0 - (d - 120.0);
} else if d > 150.0 && d <= 180.0 {
val = (d - 150.0) * 2.0;
} else if d > 180.0 && d <= 300.0 {
val = 0.0;
}
match aspector_id {
2 => { if (d - 90.0).abs() < 1e-1 { val = 60.0; }
},
4 => { if (d - 120.0).abs() < 1e-1 { val = 60.0; }
if (d - 240.0).abs() < 1e-1 { val = 60.0; }
},
6 => { if (d - 60.0).abs() < 1e-1 { val = 60.0; }
if (d - 270.0).abs() < 1e-1 { val = 60.0; }
},
_ => {}
}
val
}
fn calculate_drik_bala(target_id: i32, target_long: f64, planets: &[PlanetInput]) -> f64 {
let mut net_strength = 0.0;
for p in planets.iter() {
if p.id == target_id { continue; }
let d = (target_long - p.longitude).rem_euclid(360.0);
let val = calculate_aspect_value(d, p.id);
let is_benefic = matches!(p.id, 1 | 3 | 4 | 5);
if is_benefic {
net_strength += val;
} else {
net_strength -= val; }
}
net_strength / 4.0 }
pub fn calculate_shadbala_profile(
planets: &[PlanetInput],
jd: f64,
ascendant: f64
) -> ShadbalaProfile {
let mut results: Vec<ShadbalaResult> = Vec::with_capacity(7);
for id in 0..7 {
let p_data = planets.iter().find(|p| p.id == id);
let long = p_data.map(|p| p.longitude).unwrap_or(0.0);
let speed = p_data.map(|p| p.speed).unwrap_or(0.0);
let sthana = calculate_sthana_bala(id, planets, jd);
let dig = calculate_dig_bala(long, id, ascendant);
let kala = 45.0; let chesta = calculate_chesta_bala(id, speed);
let naisargika = match id {
0 => 60.0, 1 => 51.43, 2 => 17.14, 3 => 25.71, 4 => 34.28, 5 => 42.85, 6 => 8.57, _ => 0.0,
};
let drik = calculate_drik_bala(id, long, planets);
let total = sthana + dig + kala + chesta + naisargika + drik;
results.push(ShadbalaResult {
total_rupas: total / 60.0,
ishta_phala: 0.0,
kashta_phala: 0.0,
sthana_bala: sthana,
dig_bala: dig,
kala_bala: kala,
chesta_bala: chesta,
naisargika_bala: naisargika,
drik_bala: drik,
});
}
ShadbalaProfile {
sun: results[0],
moon: results[1],
mars: results[2],
mercury: results[3],
jupiter: results[4],
venus: results[5],
saturn: results[6],
}
}
pub fn calculate_planet_shadbala(
long: f64,
planet_id: i32,
jd: f64,
ascendant: f64
) -> ShadbalaResult {
let planets = vec![PlanetInput { id: planet_id, longitude: long, speed: 1.0 }];
let profile = calculate_shadbala_profile(&planets, jd, ascendant);
match planet_id {
0 => profile.sun,
1 => profile.moon,
2 => profile.mars,
3 => profile.mercury,
4 => profile.jupiter,
5 => profile.venus,
6 => profile.saturn,
_ => profile.sun }
}