from datetime import date

from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.views.generic import UpdateView
from django.db.models import Q, F
from django.utils.timezone import datetime
from ..forms import EventModerateForm
from ..models import Event


class EventModerateView(
    SuccessMessageMixin,
    PermissionRequiredMixin,
    LoginRequiredMixin,
    UpdateView,
):
    model = Event
    permission_required = "agenda_culturel.change_event"
    template_name = "agenda_culturel/event_form_moderate.html"
    form_class = EventModerateForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["is_moderation_expert"] = (
            self.request.user.userprofile.is_moderation_expert
        )
        return kwargs

    def get_success_message(self, cleaned_data):
        txt = (
            _(" A message has been sent to the person who proposed the event.")
            if hasattr(self, "with_msg") and self.with_msg
            else ""
        )
        return mark_safe(
            _('The event <a href="{}">{}</a> has been moderated with success.').format(
                self.object.get_absolute_url(), self.object.title
            )
            + txt
        )

    def is_moderate_next(self):
        return "after" in self.request.path.split("/")

    def is_moderate_back(self):
        return "back" in self.request.path.split("/")

    def is_moderate_force(self):
        return "moderate-force" in self.request.path.split("/")

    def is_starting_moderation(self):
        return "pk" not in self.kwargs

    def is_moderation_from_date(self):
        return "m" in self.kwargs and "y" in self.kwargs and "d" in self.kwargs

    def get_next_event(start_day, start_time, opk):
        # select non moderated events
        qs = Event.objects.filter(moderated_date__isnull=True)

        # select events after the current one
        if start_time:
            qs = qs.filter(
                Q(start_day__gt=start_day)
                | (
                    Q(start_day=start_day)
                    & (Q(start_time__isnull=True) | Q(start_time__gt=start_time))
                )
            )
        else:
            qs = qs.filter(Q(start_day__gte=start_day) & ~Q(pk=opk))

        # get only possibly representative events
        qs = qs.filter(
            Q(other_versions__isnull=True)
            | Q(other_versions__representative=F("pk"))
            | Q(other_versions__representative__isnull=True)
        )

        # remove trash events
        qs = qs.filter(~Q(status=Event.STATUS.TRASH))

        # sort by datetime
        qs = qs.order_by("start_day", "start_time")

        return qs.first()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.is_moderate_next():
            context["pred"] = self.kwargs["pred"]
        return context

    def get_object(self, queryset=None):
        if self.is_starting_moderation():
            now = datetime.now()
            event = EventModerateView.get_next_event(now.date(), now.time(), None)
        else:
            event = super().get_object(queryset)
        if event.status == Event.STATUS.DRAFT:
            event.status = Event.STATUS.PUBLISHED
        if self.is_moderate_back():
            pred = Event.objects.filter(pk=self.kwargs["pred"]).first()
            pred.free_modification_lock(self.request.user)
        if self.is_moderate_force():
            event.free_modification_lock(self.request.user, False)
        return event

    def post(self, request, *args, **kwargs):
        try:
            return super().post(request, args, kwargs)
        except Http404:
            return HttpResponseRedirect(
                reverse_lazy("error_next_event", args=[self.object.pk])
            )

    def form_valid(self, form):
        form.instance.set_no_modification_date_changed()
        form.instance.set_in_moderation_process()
        form.instance.set_processing_user(self.request.user)
        self.with_msg = form.instance.notify_if_required(self.request)
        return super().form_valid(form)

    def get_success_url(self):
        if "save_and_next" in self.request.POST:
            return reverse_lazy("moderate_event_next", args=[self.object.pk])
        elif "save_and_edit_local" in self.request.POST:
            return reverse_lazy("edit_event", args=[self.object.get_local_version().pk])
        else:
            return self.object.get_absolute_url()


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_event")
def moderate_event_next(request, pk):
    # current event
    obj = Event.objects.filter(pk=pk).first()
    # free lock
    obj.free_modification_lock(request.user)
    start_day = obj.start_day
    start_time = obj.start_time

    next_obj = EventModerateView.get_next_event(start_day, start_time, pk)
    if next_obj is None:
        return render(
            request,
            "agenda_culturel/event_next_error_message.html",
            {"pk": pk, "object": obj},
        )
    else:
        return HttpResponseRedirect(
            reverse_lazy("moderate_event_step", args=[next_obj.pk, obj.pk])
        )


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_event")
def moderate_from_date(request, y, m, d):
    d = date(y, m, d)
    obj = EventModerateView.get_next_event(d, None, None)
    return HttpResponseRedirect(reverse_lazy("moderate_event", args=[obj.pk]))
