use chrono::NaiveDate;
use crate::rules::{check, RuleContext};
use shaum_types::{FastingAnalysis, FastingStatus};
use shaum_types::ShaumError;
pub trait ShaumDateExt {
#[deprecated(since = "0.4.0", note = "Use try_status() for safe error handling")]
fn status(&self) -> FastingStatus;
fn try_status(&self) -> Result<FastingStatus, ShaumError>;
#[deprecated(since = "0.4.0", note = "Use status() or try_status() instead")]
fn fasting_status(&self) -> FastingStatus;
fn fasting_analysis(&self) -> FastingAnalysis;
fn try_fasting_analysis(&self) -> Result<FastingAnalysis, ShaumError>;
fn analyze_with(&self, ctx: &RuleContext) -> FastingAnalysis;
fn is_wajib(&self) -> bool;
fn is_haram(&self) -> bool;
fn is_sunnah(&self) -> bool;
fn is_makruh(&self) -> bool;
fn is_mubah(&self) -> bool;
fn next_sunnah(&self) -> Option<NaiveDate>;
fn next_wajib(&self) -> Option<NaiveDate>;
}
impl ShaumDateExt for NaiveDate {
fn status(&self) -> FastingStatus {
check(*self, &RuleContext::default()).unwrap().primary_status
}
fn try_status(&self) -> Result<FastingStatus, ShaumError> {
check(*self, &RuleContext::default()).map(|a| a.primary_status)
}
#[allow(deprecated)]
fn fasting_status(&self) -> FastingStatus {
self.try_status().expect("Fasting status failed")
}
fn fasting_analysis(&self) -> FastingAnalysis {
check(*self, &RuleContext::default()).expect("Fasting analysis failed")
}
fn try_fasting_analysis(&self) -> Result<FastingAnalysis, ShaumError> {
check(*self, &RuleContext::default())
}
fn analyze_with(&self, ctx: &RuleContext) -> FastingAnalysis {
check(*self, ctx).expect("Fasting analysis failed")
}
fn is_wajib(&self) -> bool { self.try_status().map(|s| s.is_wajib()).unwrap_or(false) }
fn is_haram(&self) -> bool { self.try_status().map(|s| s.is_haram()).unwrap_or(false) }
fn is_sunnah(&self) -> bool { self.try_status().map(|s| s.is_sunnah()).unwrap_or(false) }
fn is_makruh(&self) -> bool { self.try_status().map(|s| s.is_makruh()).unwrap_or(false) }
fn is_mubah(&self) -> bool { self.try_status().map(|s| s.is_mubah()).unwrap_or(false) }
fn next_sunnah(&self) -> Option<NaiveDate> {
let mut d = *self;
for _ in 0..400 {
d = d.succ_opt()?;
if let Ok(s) = d.try_status() {
if s.is_sunnah() { return Some(d); }
} else {
return None; }
}
None
}
fn next_wajib(&self) -> Option<NaiveDate> {
let mut d = *self;
for _ in 0..400 {
d = d.succ_opt()?;
if let Ok(s) = d.try_status() {
if s.is_wajib() { return Some(d); }
} else {
return None;
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(deprecated)]
fn test_extension_trait() {
let date = NaiveDate::from_ymd_opt(2024, 3, 11).unwrap();
let _status = date.try_status().unwrap();
let _analysis = date.fasting_analysis();
}
#[test]
fn test_try_status_out_of_range() {
let bad_date = NaiveDate::from_ymd_opt(3000, 1, 1).unwrap();
assert!(bad_date.try_status().is_err());
}
#[test]
fn test_analyze_with_custom_context() {
use shaum_types::Madhab;
let date = NaiveDate::from_ymd_opt(2024, 3, 11).unwrap();
let ctx = RuleContext::new().madhab(Madhab::Hanafi);
let analysis = date.analyze_with(&ctx);
assert!(analysis.primary_status >= FastingStatus::Mubah);
}
}