"""
Provides data on days off work (based on public holidays + manual inputs)
"""

from functools import lru_cache
from datetime import date, datetime, timedelta
import re
from typing import Tuple, Iterator, List, Union


from my.config.holidays_data import HOLIDAYS_DATA


# pip3 install workalendar
from workalendar.europe import UnitedKingdom # type: ignore
cal = UnitedKingdom() # TODO FIXME specify in config
# TODO that should depend on country/'location' of residence I suppose?


Dateish = Union[datetime, date, str]


def as_date(dd: Dateish) -> date:
    if isinstance(dd, datetime):
        return dd.date()
    elif isinstance(dd, date):
        return dd
    else:
        return as_date(datetime.strptime(dd, '%Y%m%d'))


@lru_cache(1)
def get_days_off_work() -> List[date]:
    return list(iter_days_off_work())


def is_day_off_work(d: date) -> bool:
    return d in get_days_off_work()


def is_working_day(d: Dateish) -> bool:
    day = as_date(d)
    if not cal.is_working_day(day):
        # public holiday -- def holiday
        return False
    # otherwise rely on work data
    return not is_day_off_work(day)


def is_holiday(d: Dateish) -> bool:
    return not(is_working_day(d))


def _iter_work_data() -> Iterator[Tuple[date, int]]:
    emitted = 0
    for x in HOLIDAYS_DATA.splitlines():
        m = re.search(r'(\d\d/\d\d/\d\d\d\d)(.*)-(\d+.\d+) days \d+.\d+ days', x)
        if m is None:
            continue
        (ds, cmnt, dayss) = m.groups()
        if 'carry over' in cmnt:
            continue

        d = datetime.strptime(ds, '%d/%m/%Y').date()
        dd, u = dayss.split('.')
        assert u == '00' # TODO meh

        yield d, int(dd)
        emitted += 1
    assert emitted > 5 # arbitrary, just a sanity check.. (TODO move to tests?)


def iter_days_off_work() -> Iterator[date]:
    for d, span in _iter_work_data():
        dd = d
        while span > 0:
            # only count it if it wasnt' a public holiday/weekend already
            if cal.is_working_day(dd):
                yield dd
                span -= 1
            dd += timedelta(days=1)


def test():
    assert is_holiday('20190101')
    assert not is_holiday('20180601')


if __name__ == '__main__':
    for d in iter_days_off_work():
        print(d, ' | ', d.strftime('%d %b'))
