use crate::time::{Date, DateError};
#[expect(
clippy::cast_sign_loss,
reason = "after validated-year computus, month is 3 or 4 and day is 1 through 31"
)]
pub fn western_easter(year: i32) -> Result<Date, DateError> {
Date::days_in_year(year)?;
let century = year / 100;
let lunar_cycle = year % 19;
let century_correction = (century - 17).div_euclid(25);
let epact =
(century - century / 4 - (century - century_correction) / 3 + 19 * lunar_cycle + 15)
.rem_euclid(30);
let corrected_epact =
epact - (epact / 28) * (1 - (epact / 28) * (29 / (epact + 1)) * ((21 - lunar_cycle) / 11));
let weekday = (year + year / 4 + corrected_epact + 2 - century + century / 4) % 7;
let offset = corrected_epact - weekday;
let month = 3 + (offset + 40) / 44;
let day = offset + 28 - 31 * (month / 4);
Date::from_ymd(year, month as u32, day as u32)
}