# ------------------------------------------------------------------------------
# Joyful models
# ------------------------------------------------------------------------------
import datetime as dt
from dateutil.parser import parse as dt_parse
from dateutil.parser import ParserError
from django.conf import settings
from django.http import Http404, JsonResponse
from django.template.response import TemplateResponse
from django.utils.translation import get_language, gettext_lazy as _
from django.utils import timezone
from ls.joyous.models.calendar import CalendarPage, DatePictures
from ls.joyous.models import (SimpleEventPage, MultidayEventPage,
                              RecurringEventPage, EventExceptionBase)
from .utils import getLocalDatetimeAtDate, ProxyPageMixin, getFirstDayOfWeek
from wagtail.contrib.routable_page.models import route
from . import __version__

# ------------------------------------------------------------------------------
class FullHoliday(dict):
    def __init__(self, date, holiday):
        self['display'] = "background"
        self['title'] = holiday
        self['start'] = date
        self['end']   = date
        self['className'] = "joy-bg-holiday"

class FullEventBase(dict):
    def __init__(self, thisEvent):
        super().__init__()
        self['title'] = thisEvent.title
        self['url']   = thisEvent.url

class FullOneOffEvent(FullEventBase):
    def __init__(self, thisEvent):
        super().__init__(thisEvent)
        page = thisEvent.page
        if page.time_from is None:
            self['start'] = page._getFromDt().date()
        else:
            self['start'] = page._getFromDt()
        if page.time_to is None:
            self['end'] = page._getToDt().date() + dt.timedelta(days=1)
        else:
            self['end'] = page._getToDt()

class FullRecurringEvent(FullEventBase):
    def __init__(self, date, thisEvent):
        super().__init__(thisEvent)
        page = thisEvent.page
        if page.time_from is None:
            self['start'] = date
        else:
            self['start'] = getLocalDatetimeAtDate(date, page.time_from, page.tz)
        endDate = date + dt.timedelta(days=page.num_days - 1)
        if page.time_to is None:
            self['end'] = endDate + dt.timedelta(days=1)
        else:
            self['end'] = getLocalDatetimeAtDate(endDate, page.time_to, page.tz)
        #TODO? self['groupId'] = page.uid

class FullEventTypeError(TypeError):
    pass

def makeFullEvent(date, thisEvent):
    page = thisEvent.page
    if isinstance(page, (SimpleEventPage, MultidayEventPage)):
        return FullOneOffEvent(thisEvent)

    elif isinstance(page, (RecurringEventPage, EventExceptionBase)):
        return FullRecurringEvent(date, thisEvent)

    else:
        raise FullEventTypeError("Unsupported page type")


FULL_VIEWS = {'L': "listYear",
              'M': "dayGridMonth",
              'W': "timeGridWeek",
              'D': "timeGridDay",}

class FullCalendarPage(ProxyPageMixin, CalendarPage):
    class Meta(ProxyPageMixin.Meta):
        verbose_name = _("full calendar page")
        verbose_name_plural = _("full calendar pages")

    @route(r"^events/$")
    def serveData(self, request):
        try:
            startDate = dt_parse(request.GET.get('start', "")).date()
            endDate   = dt_parse(request.GET.get('end', "")).date()
        except ParserError:
            raise Http404("invalid parameters")
        fullEvents = []
        evods = self._getEventsByDay(request, startDate, endDate)
        for evod in evods:
            if evod.holiday:
                fullEvents.append(FullHoliday(evod.date, evod.holiday))

            if evod.date == startDate:
                events = evod.all_events
            else:
                events = evod.days_events
            for thisEvent in events:
                fullEvents.append(makeFullEvent(evod.date, thisEvent))
        return JsonResponse(fullEvents, safe=False)

    @route(r"^month/$")
    @route(r"^{YYYY}/{MM}/$".format(**DatePictures))
    def serveMonth(self, request, year=None, month=None):
        return self.serveFull(request)

    @route(r"^week/$")
    @route(r"^{YYYY}/W{WW}/$".format(**DatePictures))
    def serveWeek(self, request, year=None, week=None):
        return self.serveFull(request)

    @route(r"^day/$")
    @route(r"^{YYYY}/{MM}/{DD}/$".format(**DatePictures))
    def serveDay(self, request, year=None, month=None, dom=None):
        return self.serveFull(request)

    @route(r"^upcoming/$")
    def serveUpcoming(self, request):
        return self.serveFull(request)

    @route(r"^past/$")
    def servePast(self, request):
        return self.serveFull(request)

    def serveFull(self, request):
        cxt = self.get_context(request)
        cxt.update({'version':  __version__,
                    'today':    timezone.localdate(),
                    'language': get_language() })
        fullViews = [FULL_VIEWS.get(choice) for choice in self.view_choices]
        cxt['viewChoices'] = ",".join(view for view in fullViews if view)
        cxt['defaultView'] = FULL_VIEWS.get(self.default_view, "dayGridMonth")
        if getFirstDayOfWeek() == 1:
            cxt['firstDayOfWeek']      = 1
            cxt['daysWithinFirstWeek'] = 4
        else:
            cxt['firstDayOfWeek']      = 0
            cxt['daysWithinFirstWeek'] = 5
        cxt.update(self._getExtraContext("full"))
        return TemplateResponse(request, "joyful/full_calendar_page.html", cxt)

for Page in (SimpleEventPage, MultidayEventPage, RecurringEventPage):
    Page.parent_page_types.append("joyful.FullCalendarPage")

# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
