use proto::MainCityTimeBin;

#[derive(Clone)]
pub struct MainCityTime {
    pub day_of_week: DayOfWeek,
    pub time_of_day: TimeOfDay,
}

impl MainCityTime {
    const DEFAULT_DAY: u32 = 1;
    const DEFAULT_TIME: u32 = 1080;

    pub fn tick(&mut self) {
        if self.time_of_day.tick() {
            self.day_of_week.next();
        }
    }

    pub fn fast_forward(&mut self, minutes: u32) {
        let days_passed = self.time_of_day.fast_forward(minutes);
        self.day_of_week.fast_forward(days_passed)
    }

    pub fn to_bin(&self) -> MainCityTimeBin {
        MainCityTimeBin {
            minutes: self.time_of_day.value(),
            day: self.day_of_week.value(),
        }
    }

    pub fn from_bin(bin: MainCityTimeBin) -> Self {
        Self {
            time_of_day: TimeOfDay::new(bin.minutes),
            day_of_week: DayOfWeek::new(bin.day),
        }
    }
}

impl Default for MainCityTime {
    fn default() -> Self {
        Self {
            day_of_week: DayOfWeek::new(Self::DEFAULT_DAY),
            time_of_day: TimeOfDay::new(Self::DEFAULT_TIME),
        }
    }
}

#[derive(Clone)]
pub struct DayOfWeek(u32);

#[derive(Clone)]
pub struct TimeOfDay(u32);

impl DayOfWeek {
    const DAYS: u32 = 7;

    pub fn new(day: u32) -> Self {
        Self(day % Self::DAYS)
    }

    pub fn value(&self) -> u32 {
        self.0
    }

    pub fn next(&mut self) {
        self.0 = (self.0 + 1) % Self::DAYS
    }

    pub fn fast_forward(&mut self, days: u32) {
        self.0 = (self.0 + days) % Self::DAYS
    }
}

impl TimeOfDay {
    const TIME_PERIOD: u32 = 1440;

    pub fn new(minutes: u32) -> Self {
        Self(minutes % Self::TIME_PERIOD)
    }

    pub fn value(&self) -> u32 {
        self.0
    }

    pub fn is_zero(&self) -> bool {
        (self.0 % Self::TIME_PERIOD) == 0
    }

    pub fn tick(&mut self) -> bool {
        self.0 = (self.0 + 1) % Self::TIME_PERIOD;
        self.is_zero()
    }

    pub fn fast_forward(&mut self, minutes: u32) -> u32 {
        self.0 += minutes;

        let days_passed = self.0 / Self::TIME_PERIOD;
        self.0 %= Self::TIME_PERIOD;

        days_passed
    }
}
