use crate::date::Date;

use super::{Interval, Schedule, TemporalUnit};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DailyRecurrenceSchedule {
    interval: Interval,
}

impl DailyRecurrenceSchedule {
    #[must_use]
    pub fn new(interval: impl Into<Interval>) -> Self {
        Self {
            interval: interval.into(),
        }
    }
    pub(super) fn daily() -> Self {
        DailyRecurrenceSchedule {
            interval: Interval::one(),
        }
    }
}

impl Schedule for DailyRecurrenceSchedule {
    fn interval(&self) -> Interval {
        self.interval
    }

    fn next_occurrence_after(&self, from: Date) -> Date {
        from.add_interval_days(self.interval)
    }

    fn into_string(self, _: Date) -> String {
        TemporalUnit::Day.print_interval(self.interval)
    }
}

#[cfg(test)]
mod tests {
    use rstest::rstest;

    use super::DailyRecurrenceSchedule;
    use crate::recurrence::{Interval, Schedule};

    #[test]
    fn interval_should_return_configured_interval() {
        let schedule = DailyRecurrenceSchedule::new(Interval::three());

        let actual = schedule.interval();

        assert_eq!(actual, Interval::three());
    }

    #[rstest]
    #[case::daily("2025-06-05", Interval::one(), "2025-06-06")]
    #[case::every_three_days("2025-06-05", Interval::three(), "2025-06-08")]
    fn next_occurrence_should_calculate_daily(
        #[case] from: &str,
        #[case] interval: Interval,
        #[case] expected: &str,
    ) {
        use crate::date::Date;

        let recurrence = DailyRecurrenceSchedule { interval };

        let from = Date::from_str_unchecked(from);
        let expected_next = Date::from_str_unchecked(expected);

        let actual_next = recurrence.next_occurrence_after(from);

        assert_eq!(actual_next, expected_next);
    }
}
