import datetime as dt
import re, logging
import zoneinfo

from .sync import Event

class IcalHelper:
    
    _WEEKDAY_MAP = {
        'Mon': 0,
        'Tue': 1,
        'Wed': 2,
        'Thu': 3,
        'Fri': 4,
        'Sat': 5,
        'Sun': 6
    }
    
    tzDE = zoneinfo.ZoneInfo('Europe/Berlin')
    deltaWeek = dt.timedelta(weeks=1)
    deltaDay = dt.timedelta(days=1)
    firstDay = dt.date(year=dt.datetime.now().year, month=1, day=1)
    
    def __init__(self):
        self._l = logging.getLogger(__name__)
        self.reTime = re.compile(r'(\d{1,2}):(\d{2})')
    
    def getStart(self, event: Event, holidays):
        firstDay = self._getFirstOccurence(event, holidays)

        if firstDay is None:
            return None, None
        return firstDay, dt.datetime.combine(firstDay, self._getTime(event.start), tzinfo=self.tzDE)

    def _getFirstWeekdayInYear(self, weekday):
        candidate = self.firstDay
        while candidate.weekday() != self._WEEKDAY_MAP[weekday]:
            candidate += self.deltaDay
        
        self._l.log(5, 'First %s in year is %s', weekday, candidate)

        return candidate
    
    def _getSortedHolidays(self, holidays):
        return sorted(holidays['holidays'], key=lambda h: h['from'])

    def _getSortedFeasts(self, holidays):
        return sorted(holidays['feasts'])
    
    def _isFeast(self, candidate, feasts):
        return candidate in feasts
    
    def _isHoliday(self, candidate, holidays):
        for h in holidays:
            if h['from'] <= candidate <= h['to']:
                return True
        
        return False

    def _getLastHolidayException(self, holidays):
        holidayList = list(self._getSortedHolidays(holidays))
        holidayList.reverse()
        lastHoliday = holidayList[0]
        lastHolidayDay = lastHoliday['to']

        feastList = list(self._getSortedFeasts(holidays))
        feastList.reverse()
        lastFeast = feastList[0]
        lastFeastDay = lastFeast

        return max(lastHolidayDay, lastFeastDay)

    def _getFirstOccurence(self, event: Event, holidays):
        firstWeekday = self._getFirstWeekdayInYear(event.day)
        

        candidate = firstWeekday
        while candidate.year == firstWeekday.year:
            if self._isFeast(candidate, holidays['feasts']):
                self._l.log(5, 'Found feast %s', candidate)
                candidate += self.deltaWeek
                continue
            
            if self._isHoliday(candidate, holidays['holidays']):
                self._l.log(5, 'Found holiday %s', candidate)
                candidate += self.deltaWeek
                continue
            
            self._l.log(5, 'Found first occurence %s', candidate)
            return candidate
        
        return None
        
        # firstWeekday.tzinfo = dt.timezone.tzname('Europe/Berlin')
    
    def _getTime(self, startStr):
        match = self.reTime.match(startStr)
        return dt.time(int(match.group(1)), int(match.group(2)))
    
    def getHolidayExceptions(self, event: Event, startDay, holidays):
        lastHolidayDay = self._getLastHolidayException(holidays)

        pointer = startDay
        exeptions = []
        while pointer <= lastHolidayDay:
            ex = dt.datetime.combine(pointer, self._getTime(event.start), tzinfo=self.tzDE)

            if self._isFeast(pointer, holidays['feasts']):
                exeptions.append(ex)

            if self._isHoliday(pointer, holidays['holidays']) and not event.external:
                exeptions.append(ex)

            pointer += self.deltaWeek
        
        if len(exeptions) > 0:
            return exeptions
        return None