// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

//! This module contains types and implementations for the Persian calendar.
//!
//! ```rust
//! use icu::calendar::{Date, DateTime};
//!
//! // `Date` type
//! let persian_date = Date::try_new_persian_date(1348, 10, 11)
//!     .expect("Failed to initialize Persian Date instance.");
//!
//! // `DateTime` type
//! let persian_datetime =
//!     DateTime::try_new_persian_datetime(1348, 10, 11, 13, 1, 0)
//!         .expect("Failed to initialize Persian DateTime instance.");
//!
//! // `Date` checks
//! assert_eq!(persian_date.year().number, 1348);
//! assert_eq!(persian_date.month().ordinal, 10);
//! assert_eq!(persian_date.day_of_month().0, 11);
//!
//! // `DateTime` checks
//! assert_eq!(persian_datetime.date.year().number, 1348);
//! assert_eq!(persian_datetime.date.month().ordinal, 10);
//! assert_eq!(persian_datetime.date.day_of_month().0, 11);
//! assert_eq!(persian_datetime.time.hour.number(), 13);
//! assert_eq!(persian_datetime.time.minute.number(), 1);
//! assert_eq!(persian_datetime.time.second.number(), 0);
//! ```

use crate::any_calendar::AnyCalendarKind;
use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic};
use crate::iso::Iso;
use crate::{types, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime, Time};
use ::tinystr::tinystr;
use calendrical_calculations::helpers::I32CastError;
use calendrical_calculations::rata_die::RataDie;

/// The Persian Calendar
///
/// The [Persian Calendar] is a solar calendar used officially by the countries of Iran and Afghanistan and many Persian-speaking regions.
/// It has 12 months and other similarities to the Gregorian Calendar
///
/// This type can be used with [`Date`] or [`DateTime`] to represent dates in this calendar.
///
/// [Persian Calendar]: https://en.wikipedia.org/wiki/Solar_Hijri_calendar
///
/// # Era codes
///
/// This calendar supports only one era code, which starts from the year of the Hijra, designated as "ah".
///
/// # Month codes
///
/// This calendar supports 12 solar month codes (`"M01" - "M12"`)
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[allow(clippy::exhaustive_structs)]
pub struct Persian;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]

/// The inner date type used for representing [`Date`]s of [`Persian`]. See [`Date`] and [`Persian`] for more details.
pub struct PersianDateInner(ArithmeticDate<Persian>);

impl CalendarArithmetic for Persian {
    type YearInfo = ();

    fn month_days(year: i32, month: u8, _data: ()) -> u8 {
        match month {
            1..=6 => 31,
            7..=11 => 30,
            12 if Self::is_leap_year(year, ()) => 30,
            12 => 29,
            _ => 0,
        }
    }

    fn months_for_every_year(_: i32, _data: ()) -> u8 {
        12
    }

    fn is_leap_year(p_year: i32, _data: ()) -> bool {
        calendrical_calculations::persian::is_leap_year(p_year, _data)
    }

    fn days_in_provided_year(year: i32, _data: ()) -> u16 {
        if Self::is_leap_year(year, ()) {
            366
        } else {
            365
        }
    }

    fn last_month_day_in_year(year: i32, _data: ()) -> (u8, u8) {
        if Self::is_leap_year(year, ()) {
            (12, 30)
        } else {
            (12, 29)
        }
    }
}

impl Calendar for Persian {
    type DateInner = PersianDateInner;
    fn date_from_codes(
        &self,
        era: types::Era,
        year: i32,
        month_code: types::MonthCode,
        day: u8,
    ) -> Result<Self::DateInner, CalendarError> {
        let year = if era.0 == tinystr!(16, "ah") || era.0 == tinystr!(16, "persian") {
            year
        } else {
            return Err(CalendarError::UnknownEra(era.0, self.debug_name()));
        };

        ArithmeticDate::new_from_codes(self, year, month_code, day).map(PersianDateInner)
    }

    fn date_from_iso(&self, iso: Date<Iso>) -> PersianDateInner {
        let fixed_iso = Iso::fixed_from_iso(*iso.inner());
        Self::fast_persian_from_fixed(fixed_iso)
    }

    fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> {
        let fixed_persian = Persian::fixed_from_fast_persian(*date);
        Iso::iso_from_fixed(fixed_persian)
    }

    fn months_in_year(&self, date: &Self::DateInner) -> u8 {
        date.0.months_in_year()
    }

    fn days_in_year(&self, date: &Self::DateInner) -> u16 {
        date.0.days_in_year()
    }

    fn days_in_month(&self, date: &Self::DateInner) -> u8 {
        date.0.days_in_month()
    }

    fn day_of_week(&self, date: &Self::DateInner) -> types::IsoWeekday {
        Iso.day_of_week(self.date_to_iso(date).inner())
    }

    fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
        date.0.offset_date(offset, &())
    }

    #[allow(clippy::field_reassign_with_default)]
    fn until(
        &self,
        date1: &Self::DateInner,
        date2: &Self::DateInner,
        _calendar2: &Self,
        _largest_unit: DateDurationUnit,
        _smallest_unit: DateDurationUnit,
    ) -> DateDuration<Self> {
        date1.0.until(date2.0, _largest_unit, _smallest_unit)
    }

    fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
        Self::year_as_persian(date.0.year)
    }

    fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
        Self::is_leap_year(date.0.year, ())
    }

    fn month(&self, date: &Self::DateInner) -> types::FormattableMonth {
        date.0.month()
    }

    fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
        date.0.day_of_month()
    }

    fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo {
        let prev_year = date.0.year.saturating_sub(1);
        let next_year = date.0.year.saturating_add(1);
        types::DayOfYearInfo {
            day_of_year: date.0.day_of_year(),
            days_in_year: date.0.days_in_year(),
            prev_year: Persian::year_as_persian(prev_year),
            days_in_prev_year: Persian::days_in_provided_year(prev_year, ()),
            next_year: Persian::year_as_persian(next_year),
        }
    }

    fn debug_name(&self) -> &'static str {
        "Persian"
    }
    // Missing any_calendar persian tests, the rest is completed
    fn any_calendar_kind(&self) -> Option<AnyCalendarKind> {
        Some(AnyCalendarKind::Persian)
    }
}

impl Persian {
    /// Constructs a new Persian Calendar
    pub fn new() -> Self {
        Self
    }

    fn fixed_from_fast_persian(p_date: PersianDateInner) -> RataDie {
        calendrical_calculations::persian::fixed_from_fast_persian(
            p_date.0.year,
            p_date.0.month,
            p_date.0.day,
        )
    }
    fn fast_persian_from_fixed(date: RataDie) -> PersianDateInner {
        let (year, month, day) =
            match calendrical_calculations::persian::fast_persian_from_fixed(date) {
                Err(I32CastError::BelowMin) => return PersianDateInner(ArithmeticDate::min_date()),
                Err(I32CastError::AboveMax) => return PersianDateInner(ArithmeticDate::max_date()),
                Ok(ymd) => ymd,
            };

        PersianDateInner(ArithmeticDate::new_unchecked(year, month, day))
    }

    fn year_as_persian(year: i32) -> types::FormattableYear {
        types::FormattableYear {
            era: types::Era(tinystr!(16, "ah")),
            number: year,
            cyclic: None,
            related_iso: None,
        }
    }
}

impl Date<Persian> {
    /// Construct new Persian Date.
    ///
    /// Has no negative years, only era is the AH/AP.
    ///
    /// ```rust
    /// use icu::calendar::Date;
    ///
    /// let date_persian = Date::try_new_persian_date(1392, 4, 25)
    ///     .expect("Failed to initialize Persian Date instance.");
    ///
    /// assert_eq!(date_persian.year().number, 1392);
    /// assert_eq!(date_persian.month().ordinal, 4);
    /// assert_eq!(date_persian.day_of_month().0, 25);
    /// ```
    pub fn try_new_persian_date(
        year: i32,
        month: u8,
        day: u8,
    ) -> Result<Date<Persian>, CalendarError> {
        ArithmeticDate::new_from_ordinals(year, month, day)
            .map(PersianDateInner)
            .map(|inner| Date::from_raw(inner, Persian))
    }
}

impl DateTime<Persian> {
    /// Construct a new Persian datetime from integers.
    ///
    /// ```rust
    /// use icu::calendar::DateTime;
    ///
    /// let datetime_persian =
    ///     DateTime::try_new_persian_datetime(474, 10, 11, 13, 1, 0)
    ///         .expect("Failed to initialize Persian DateTime instance.");
    ///
    /// assert_eq!(datetime_persian.date.year().number, 474);
    /// assert_eq!(datetime_persian.date.month().ordinal, 10);
    /// assert_eq!(datetime_persian.date.day_of_month().0, 11);
    /// assert_eq!(datetime_persian.time.hour.number(), 13);
    /// assert_eq!(datetime_persian.time.minute.number(), 1);
    /// assert_eq!(datetime_persian.time.second.number(), 0);
    /// ```
    pub fn try_new_persian_datetime(
        year: i32,
        month: u8,
        day: u8,
        hour: u8,
        minute: u8,
        second: u8,
    ) -> Result<DateTime<Persian>, CalendarError> {
        Ok(DateTime {
            date: Date::try_new_persian_date(year, month, day)?,
            time: Time::try_new(hour, minute, second, 0)?,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[derive(Debug)]
    struct DateCase {
        year: i32,
        month: u8,
        day: u8,
    }

    static TEST_FIXED_DATE: [i64; 21] = [
        656786, 664224, 671401, 694799, 702806, 704424, 708842, 709409, 709580, 727274, 728714,
        739330, 739331, 744313, 763436, 763437, 764652, 775123, 775488, 775489, 1317874,
    ];

    // Test data are provided for the range 1178-3000 AP, for which
    // we know the 33-year rule, with the override table, matches the
    // astronomical calculations based on the 52.5 degrees east meridian.
    static CASES: [DateCase; 21] = [
        // First year for which 33-year rule matches the astronomical calculation
        DateCase {
            year: 1178,
            month: 1,
            day: 1,
        },
        DateCase {
            year: 1198,
            month: 5,
            day: 10,
        },
        DateCase {
            year: 1218,
            month: 1,
            day: 7,
        },
        DateCase {
            year: 1282,
            month: 1,
            day: 29,
        },
        // The beginning of the year the calendar was adopted
        DateCase {
            year: 1304,
            month: 1,
            day: 1,
        },
        DateCase {
            year: 1308,
            month: 6,
            day: 3,
        },
        DateCase {
            year: 1320,
            month: 7,
            day: 7,
        },
        DateCase {
            year: 1322,
            month: 1,
            day: 29,
        },
        DateCase {
            year: 1322,
            month: 7,
            day: 14,
        },
        DateCase {
            year: 1370,
            month: 12,
            day: 27,
        },
        DateCase {
            year: 1374,
            month: 12,
            day: 6,
        },
        // First day that the 2820-year rule fails
        DateCase {
            year: 1403,
            month: 12,
            day: 30,
        },
        // First Nowruz that the 2820-year rule fails
        DateCase {
            year: 1404,
            month: 1,
            day: 1,
        },
        DateCase {
            year: 1417,
            month: 8,
            day: 19,
        },
        // First day the unmodified astronomical algorithm fails
        DateCase {
            year: 1469,
            month: 12,
            day: 30,
        },
        // First Nowruz the unmodified astronomical algorithm fails
        DateCase {
            year: 1470,
            month: 1,
            day: 1,
        },
        DateCase {
            year: 1473,
            month: 4,
            day: 28,
        },
        // Last year the 33-year rule matches the modified astronomical calculation
        DateCase {
            year: 1501,
            month: 12,
            day: 29,
        },
        DateCase {
            year: 1502,
            month: 12,
            day: 29,
        },
        DateCase {
            year: 1503,
            month: 1,
            day: 1,
        },
        DateCase {
            year: 2988,
            month: 1,
            day: 1,
        },
    ];

    fn days_in_provided_year_core(year: i32) -> u16 {
        let fixed_year =
            calendrical_calculations::persian::fixed_from_fast_persian(year, 1, 1).to_i64_date();
        let next_fixed_year =
            calendrical_calculations::persian::fixed_from_fast_persian(year + 1, 1, 1)
                .to_i64_date();

        (next_fixed_year - fixed_year) as u16
    }

    #[test]
    fn test_persian_leap_year() {
        let mut leap_years: [i32; 21] = [0; 21];
        // These values were computed from the "Calendrical Calculations" reference code output
        let expected_values = [
            false, false, true, false, true, false, false, false, false, true, false, true, false,
            false, true, false, false, false, false, true, true,
        ];

        for (index, case) in CASES.iter().enumerate() {
            leap_years[index] = case.year;
        }
        for (year, bool) in leap_years.iter().zip(expected_values.iter()) {
            assert_eq!(Persian::is_leap_year(*year, ()), *bool);
        }
    }

    #[test]
    fn days_in_provided_year_test() {
        for case in CASES.iter() {
            assert_eq!(
                days_in_provided_year_core(case.year),
                Persian::days_in_provided_year(case.year, ())
            );
        }
    }

    #[test]
    fn test_fixed_from_persian() {
        for (case, f_date) in CASES.iter().zip(TEST_FIXED_DATE.iter()) {
            let date = Date::try_new_persian_date(case.year, case.month, case.day).unwrap();

            assert_eq!(
                Persian::fixed_from_fast_persian(*date.inner()).to_i64_date(),
                *f_date,
                "{case:?}"
            );
        }
    }
    #[test]
    fn test_persian_from_fixed() {
        for (case, f_date) in CASES.iter().zip(TEST_FIXED_DATE.iter()) {
            let date = Date::try_new_persian_date(case.year, case.month, case.day).unwrap();
            assert_eq!(
                Persian::fast_persian_from_fixed(RataDie::new(*f_date)),
                date.inner,
                "{case:?}"
            );
        }
    }

    #[test]
    fn test_day_of_year_info() {
        #[derive(Debug)]
        struct TestCase {
            input: i32,
            expected_prev: i32,
            expected_next: i32,
        }

        let test_cases = [
            TestCase {
                input: 0,
                expected_prev: -1,
                expected_next: 1,
            },
            TestCase {
                input: i32::MAX,
                expected_prev: i32::MAX - 1,
                expected_next: i32::MAX, // can't go above i32::MAX
            },
            TestCase {
                input: i32::MIN + 1,
                expected_prev: i32::MIN,
                expected_next: i32::MIN + 2,
            },
            TestCase {
                input: i32::MIN,
                expected_prev: i32::MIN, // can't go below i32::MIN
                expected_next: i32::MIN + 1,
            },
        ];

        for case in test_cases {
            let date = Date::try_new_persian_date(case.input, 1, 1).unwrap();
            let info = Persian::day_of_year_info(&Persian, date.inner());

            assert_eq!(info.prev_year.number, case.expected_prev, "{:?}", case);
            assert_eq!(info.next_year.number, case.expected_next, "{:?}", case);
        }
    }

    // From https://calendar.ut.ac.ir/Fa/News/Data/Doc/KabiseShamsi1206-1498-new.pdf
    // Plain text version at https://github.com/roozbehp/persiancalendar/blob/main/kabise.txt
    static CALENDAR_UT_AC_IR_TEST_DATA: [(i32, bool, i32, u32, u32); 293] = [
        (1206, false, 1827, 3, 22),
        (1207, false, 1828, 3, 21),
        (1208, false, 1829, 3, 21),
        (1209, false, 1830, 3, 21),
        (1210, true, 1831, 3, 21),
        (1211, false, 1832, 3, 21),
        (1212, false, 1833, 3, 21),
        (1213, false, 1834, 3, 21),
        (1214, true, 1835, 3, 21),
        (1215, false, 1836, 3, 21),
        (1216, false, 1837, 3, 21),
        (1217, false, 1838, 3, 21),
        (1218, true, 1839, 3, 21),
        (1219, false, 1840, 3, 21),
        (1220, false, 1841, 3, 21),
        (1221, false, 1842, 3, 21),
        (1222, true, 1843, 3, 21),
        (1223, false, 1844, 3, 21),
        (1224, false, 1845, 3, 21),
        (1225, false, 1846, 3, 21),
        (1226, true, 1847, 3, 21),
        (1227, false, 1848, 3, 21),
        (1228, false, 1849, 3, 21),
        (1229, false, 1850, 3, 21),
        (1230, true, 1851, 3, 21),
        (1231, false, 1852, 3, 21),
        (1232, false, 1853, 3, 21),
        (1233, false, 1854, 3, 21),
        (1234, true, 1855, 3, 21),
        (1235, false, 1856, 3, 21),
        (1236, false, 1857, 3, 21),
        (1237, false, 1858, 3, 21),
        (1238, true, 1859, 3, 21),
        (1239, false, 1860, 3, 21),
        (1240, false, 1861, 3, 21),
        (1241, false, 1862, 3, 21),
        (1242, false, 1863, 3, 21),
        (1243, true, 1864, 3, 20),
        (1244, false, 1865, 3, 21),
        (1245, false, 1866, 3, 21),
        (1246, false, 1867, 3, 21),
        (1247, true, 1868, 3, 20),
        (1248, false, 1869, 3, 21),
        (1249, false, 1870, 3, 21),
        (1250, false, 1871, 3, 21),
        (1251, true, 1872, 3, 20),
        (1252, false, 1873, 3, 21),
        (1253, false, 1874, 3, 21),
        (1254, false, 1875, 3, 21),
        (1255, true, 1876, 3, 20),
        (1256, false, 1877, 3, 21),
        (1257, false, 1878, 3, 21),
        (1258, false, 1879, 3, 21),
        (1259, true, 1880, 3, 20),
        (1260, false, 1881, 3, 21),
        (1261, false, 1882, 3, 21),
        (1262, false, 1883, 3, 21),
        (1263, true, 1884, 3, 20),
        (1264, false, 1885, 3, 21),
        (1265, false, 1886, 3, 21),
        (1266, false, 1887, 3, 21),
        (1267, true, 1888, 3, 20),
        (1268, false, 1889, 3, 21),
        (1269, false, 1890, 3, 21),
        (1270, false, 1891, 3, 21),
        (1271, true, 1892, 3, 20),
        (1272, false, 1893, 3, 21),
        (1273, false, 1894, 3, 21),
        (1274, false, 1895, 3, 21),
        (1275, false, 1896, 3, 20),
        (1276, true, 1897, 3, 20),
        (1277, false, 1898, 3, 21),
        (1278, false, 1899, 3, 21),
        (1279, false, 1900, 3, 21),
        (1280, true, 1901, 3, 21),
        (1281, false, 1902, 3, 22),
        (1282, false, 1903, 3, 22),
        (1283, false, 1904, 3, 21),
        (1284, true, 1905, 3, 21),
        (1285, false, 1906, 3, 22),
        (1286, false, 1907, 3, 22),
        (1287, false, 1908, 3, 21),
        (1288, true, 1909, 3, 21),
        (1289, false, 1910, 3, 22),
        (1290, false, 1911, 3, 22),
        (1291, false, 1912, 3, 21),
        (1292, true, 1913, 3, 21),
        (1293, false, 1914, 3, 22),
        (1294, false, 1915, 3, 22),
        (1295, false, 1916, 3, 21),
        (1296, true, 1917, 3, 21),
        (1297, false, 1918, 3, 22),
        (1298, false, 1919, 3, 22),
        (1299, false, 1920, 3, 21),
        (1300, true, 1921, 3, 21),
        (1301, false, 1922, 3, 22),
        (1302, false, 1923, 3, 22),
        (1303, false, 1924, 3, 21),
        (1304, true, 1925, 3, 21),
        (1305, false, 1926, 3, 22),
        (1306, false, 1927, 3, 22),
        (1307, false, 1928, 3, 21),
        (1308, false, 1929, 3, 21),
        (1309, true, 1930, 3, 21),
        (1310, false, 1931, 3, 22),
        (1311, false, 1932, 3, 21),
        (1312, false, 1933, 3, 21),
        (1313, true, 1934, 3, 21),
        (1314, false, 1935, 3, 22),
        (1315, false, 1936, 3, 21),
        (1316, false, 1937, 3, 21),
        (1317, true, 1938, 3, 21),
        (1318, false, 1939, 3, 22),
        (1319, false, 1940, 3, 21),
        (1320, false, 1941, 3, 21),
        (1321, true, 1942, 3, 21),
        (1322, false, 1943, 3, 22),
        (1323, false, 1944, 3, 21),
        (1324, false, 1945, 3, 21),
        (1325, true, 1946, 3, 21),
        (1326, false, 1947, 3, 22),
        (1327, false, 1948, 3, 21),
        (1328, false, 1949, 3, 21),
        (1329, true, 1950, 3, 21),
        (1330, false, 1951, 3, 22),
        (1331, false, 1952, 3, 21),
        (1332, false, 1953, 3, 21),
        (1333, true, 1954, 3, 21),
        (1334, false, 1955, 3, 22),
        (1335, false, 1956, 3, 21),
        (1336, false, 1957, 3, 21),
        (1337, true, 1958, 3, 21),
        (1338, false, 1959, 3, 22),
        (1339, false, 1960, 3, 21),
        (1340, false, 1961, 3, 21),
        (1341, false, 1962, 3, 21),
        (1342, true, 1963, 3, 21),
        (1343, false, 1964, 3, 21),
        (1344, false, 1965, 3, 21),
        (1345, false, 1966, 3, 21),
        (1346, true, 1967, 3, 21),
        (1347, false, 1968, 3, 21),
        (1348, false, 1969, 3, 21),
        (1349, false, 1970, 3, 21),
        (1350, true, 1971, 3, 21),
        (1351, false, 1972, 3, 21),
        (1352, false, 1973, 3, 21),
        (1353, false, 1974, 3, 21),
        (1354, true, 1975, 3, 21),
        (1355, false, 1976, 3, 21),
        (1356, false, 1977, 3, 21),
        (1357, false, 1978, 3, 21),
        (1358, true, 1979, 3, 21),
        (1359, false, 1980, 3, 21),
        (1360, false, 1981, 3, 21),
        (1361, false, 1982, 3, 21),
        (1362, true, 1983, 3, 21),
        (1363, false, 1984, 3, 21),
        (1364, false, 1985, 3, 21),
        (1365, false, 1986, 3, 21),
        (1366, true, 1987, 3, 21),
        (1367, false, 1988, 3, 21),
        (1368, false, 1989, 3, 21),
        (1369, false, 1990, 3, 21),
        (1370, true, 1991, 3, 21),
        (1371, false, 1992, 3, 21),
        (1372, false, 1993, 3, 21),
        (1373, false, 1994, 3, 21),
        (1374, false, 1995, 3, 21),
        (1375, true, 1996, 3, 20),
        (1376, false, 1997, 3, 21),
        (1377, false, 1998, 3, 21),
        (1378, false, 1999, 3, 21),
        (1379, true, 2000, 3, 20),
        (1380, false, 2001, 3, 21),
        (1381, false, 2002, 3, 21),
        (1382, false, 2003, 3, 21),
        (1383, true, 2004, 3, 20),
        (1384, false, 2005, 3, 21),
        (1385, false, 2006, 3, 21),
        (1386, false, 2007, 3, 21),
        (1387, true, 2008, 3, 20),
        (1388, false, 2009, 3, 21),
        (1389, false, 2010, 3, 21),
        (1390, false, 2011, 3, 21),
        (1391, true, 2012, 3, 20),
        (1392, false, 2013, 3, 21),
        (1393, false, 2014, 3, 21),
        (1394, false, 2015, 3, 21),
        (1395, true, 2016, 3, 20),
        (1396, false, 2017, 3, 21),
        (1397, false, 2018, 3, 21),
        (1398, false, 2019, 3, 21),
        (1399, true, 2020, 3, 20),
        (1400, false, 2021, 3, 21),
        (1401, false, 2022, 3, 21),
        (1402, false, 2023, 3, 21),
        (1403, true, 2024, 3, 20),
        (1404, false, 2025, 3, 21),
        (1405, false, 2026, 3, 21),
        (1406, false, 2027, 3, 21),
        (1407, false, 2028, 3, 20),
        (1408, true, 2029, 3, 20),
        (1409, false, 2030, 3, 21),
        (1410, false, 2031, 3, 21),
        (1411, false, 2032, 3, 20),
        (1412, true, 2033, 3, 20),
        (1413, false, 2034, 3, 21),
        (1414, false, 2035, 3, 21),
        (1415, false, 2036, 3, 20),
        (1416, true, 2037, 3, 20),
        (1417, false, 2038, 3, 21),
        (1418, false, 2039, 3, 21),
        (1419, false, 2040, 3, 20),
        (1420, true, 2041, 3, 20),
        (1421, false, 2042, 3, 21),
        (1422, false, 2043, 3, 21),
        (1423, false, 2044, 3, 20),
        (1424, true, 2045, 3, 20),
        (1425, false, 2046, 3, 21),
        (1426, false, 2047, 3, 21),
        (1427, false, 2048, 3, 20),
        (1428, true, 2049, 3, 20),
        (1429, false, 2050, 3, 21),
        (1430, false, 2051, 3, 21),
        (1431, false, 2052, 3, 20),
        (1432, true, 2053, 3, 20),
        (1433, false, 2054, 3, 21),
        (1434, false, 2055, 3, 21),
        (1435, false, 2056, 3, 20),
        (1436, true, 2057, 3, 20),
        (1437, false, 2058, 3, 21),
        (1438, false, 2059, 3, 21),
        (1439, false, 2060, 3, 20),
        (1440, false, 2061, 3, 20),
        (1441, true, 2062, 3, 20),
        (1442, false, 2063, 3, 21),
        (1443, false, 2064, 3, 20),
        (1444, false, 2065, 3, 20),
        (1445, true, 2066, 3, 20),
        (1446, false, 2067, 3, 21),
        (1447, false, 2068, 3, 20),
        (1448, false, 2069, 3, 20),
        (1449, true, 2070, 3, 20),
        (1450, false, 2071, 3, 21),
        (1451, false, 2072, 3, 20),
        (1452, false, 2073, 3, 20),
        (1453, true, 2074, 3, 20),
        (1454, false, 2075, 3, 21),
        (1455, false, 2076, 3, 20),
        (1456, false, 2077, 3, 20),
        (1457, true, 2078, 3, 20),
        (1458, false, 2079, 3, 21),
        (1459, false, 2080, 3, 20),
        (1460, false, 2081, 3, 20),
        (1461, true, 2082, 3, 20),
        (1462, false, 2083, 3, 21),
        (1463, false, 2084, 3, 20),
        (1464, false, 2085, 3, 20),
        (1465, true, 2086, 3, 20),
        (1466, false, 2087, 3, 21),
        (1467, false, 2088, 3, 20),
        (1468, false, 2089, 3, 20),
        (1469, true, 2090, 3, 20),
        (1470, false, 2091, 3, 21),
        (1471, false, 2092, 3, 20),
        (1472, false, 2093, 3, 20),
        (1473, false, 2094, 3, 20),
        (1474, true, 2095, 3, 20),
        (1475, false, 2096, 3, 20),
        (1476, false, 2097, 3, 20),
        (1477, false, 2098, 3, 20),
        (1478, true, 2099, 3, 20),
        (1479, false, 2100, 3, 21),
        (1480, false, 2101, 3, 21),
        (1481, false, 2102, 3, 21),
        (1482, true, 2103, 3, 21),
        (1483, false, 2104, 3, 21),
        (1484, false, 2105, 3, 21),
        (1485, false, 2106, 3, 21),
        (1486, true, 2107, 3, 21),
        (1487, false, 2108, 3, 21),
        (1488, false, 2109, 3, 21),
        (1489, false, 2110, 3, 21),
        (1490, true, 2111, 3, 21),
        (1491, false, 2112, 3, 21),
        (1492, false, 2113, 3, 21),
        (1493, false, 2114, 3, 21),
        (1494, true, 2115, 3, 21),
        (1495, false, 2116, 3, 21),
        (1496, false, 2117, 3, 21),
        (1497, false, 2118, 3, 21),
        (1498, true, 2119, 3, 21),
    ];

    #[test]
    fn test_calendar_ut_ac_ir_data() {
        for (p_year, leap, iso_year, iso_month, iso_day) in CALENDAR_UT_AC_IR_TEST_DATA.iter() {
            assert_eq!(Persian::is_leap_year(*p_year, ()), *leap);
            let persian_date = Date::try_new_persian_date(*p_year, 1, 1).unwrap();
            let iso_date = persian_date.to_calendar(Iso);
            assert_eq!(iso_date.year().number, *iso_year);
            assert_eq!(iso_date.month().ordinal, *iso_month);
            assert_eq!(iso_date.day_of_month().0, *iso_day);
        }
    }
}
