# coding: utf-8
import logging
from datetime import date, timedelta

import arrow
from django.utils.timezone import localtime
from ids.registry import registry

logger = logging.getLogger(__name__)

workday_cache = {}


class WorkdayChecker(object):
    def __init__(self):
        self.cache = {}

    def is_workday(self, day):
        global workday_cache

        if day not in workday_cache:
            try:
                self._fetch(day)

            except Exception:
                logger.exception('IDS could not fetch calendar')

        # On failures consider any day as working one
        return workday_cache.get(day, True)

    @staticmethod
    def _fetch(day):
        global workday_cache

        start_date = date(day.year, day.month, 1)
        end_date = start_date + timedelta(days=30)

        repo = registry.get_repository(
            'calendar', 'holidays', user_agent='procu'
        )

        days = repo.get(
            {
                'start_date': start_date,
                'end_date': end_date,
                'out_mode': 'all',
                'who_am_i': 'procu',
            }
        )

        for day in days:
            workday_cache[day['date']] = day['day-type'] == 'weekday'


def working_timedelta(d1, d2):
    assert d1 <= d2, "{} {}".format(d1, d2)

    d1 = arrow.Arrow.fromdatetime(localtime(d1))
    d2 = arrow.Arrow.fromdatetime(localtime(d2))

    spans = [list(s) for s in arrow.Arrow.span_range('day', d1, d2)]
    spans[0][0] = d1
    spans[-1][1] = d2

    wc = WorkdayChecker()

    delta = timedelta()

    for start, end in spans:
        if wc.is_workday(start.date()):
            if end != d2:
                end = arrow.Arrow.fromtimestamp(
                    round(end.float_timestamp), end.tzinfo
                )
            delta += end - start

    return delta


WORKING_HOURS_START = 10
WORKING_HOURS_END = 20


def jump_working_hours(start=None, *, hours: int):

    target = localtime(start)

    if hours > 24 * 10:
        return target + timedelta(hours=hours)

    wc = WorkdayChecker()

    elapsed = 0

    while elapsed < hours:
        target += timedelta(hours=1)

        if (
            wc.is_workday(target.date())
            and WORKING_HOURS_START <= target.hour < WORKING_HOURS_END
        ):
            elapsed += 1

    return target
