from datetime import datetime

from django.contrib import messages
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.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import UpdateView, CreateView, DeleteView

from ..forms import CategorisationRuleImportForm, CategorisationForm
from ..models import Event, CategorisationRule, Category


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.view_categorisationrule")
def categorisation_rules(request):
    paginator = Paginator(
        CategorisationRule.objects.all()
        .order_by("pk")
        .select_related("category")
        .select_related("place"),
        100,
    )
    page = request.GET.get("page")

    try:
        response = paginator.page(page)
    except PageNotAnInteger:
        response = paginator.page(1)
    except EmptyPage:
        response = paginator.page(paginator.num_pages)

    return render(
        request,
        "agenda_culturel/categorisation_rules.html",
        {"paginator_filter": response},
    )


class CategorisationRuleCreateView(
    LoginRequiredMixin, PermissionRequiredMixin, CreateView
):
    model = CategorisationRule
    permission_required = "agenda_culturel.add_categorisationrule"
    success_url = reverse_lazy("categorisation_rules")
    form_class = CategorisationRuleImportForm


class CategorisationRuleUpdateView(
    SuccessMessageMixin,
    PermissionRequiredMixin,
    LoginRequiredMixin,
    UpdateView,
):
    model = CategorisationRule
    permission_required = "agenda_culturel.change_categorisationrule"
    form_class = CategorisationRuleImportForm
    success_url = reverse_lazy("categorisation_rules")
    success_message = _("The categorisation rule has been successfully modified.")


class CategorisationRuleDeleteView(
    SuccessMessageMixin,
    PermissionRequiredMixin,
    LoginRequiredMixin,
    DeleteView,
):
    model = CategorisationRule
    permission_required = "agenda_culturel.delete_categorisationrule"
    success_url = reverse_lazy("categorisation_rules")
    success_message = _("The categorisation rule has been successfully deleted.")


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.apply_categorisationrules")
def apply_categorisation_rules(request):
    if request.method == "POST":
        form = CategorisationForm(request.POST)
        if form.is_valid():
            nb = 0
            for epk, c in form.get_validated():
                e = Event.objects.get(pk=epk)
                cat = Category.objects.filter(name=c).first()
                e.category = cat
                e.save()
                nb += 1

            if nb != 0:
                if nb == 1:
                    messages.success(
                        request,
                        _(
                            "The rules were successfully applied and 1 event was categorised."
                        ),
                    )
                else:
                    messages.success(
                        request,
                        _(
                            "The rules were successfully applied and {} events were categorised."
                        ).format(nb),
                    )
            else:
                messages.info(
                    request,
                    _(
                        "The rules were successfully applied and no events were categorised."
                    ),
                )

            return HttpResponseRedirect(reverse_lazy("categorisation_rules"))
        else:
            return render(
                request,
                "agenda_culturel/categorise_events_form.html",
                context={"form": form},
            )
    else:
        # first we check if events are not correctly categorised
        to_categorise = []
        events = (
            Event.objects.filter(start_day__gte=datetime.now())
            .exclude(category=Category.get_default_category_id())
            .exclude(category=None)
            .select_related("exact_location")
            .select_related("category")
        )
        for e in events:
            c = CategorisationRule.get_category_from_rules(e)
            if c and c != e.category:
                to_categorise.append((e, c))

        # then we apply rules on events without category
        nb = 0
        to_save = []
        events = (
            Event.objects.filter(start_day__gte=datetime.now())
            .filter(Q(category=Category.get_default_category_id()) | Q(category=None))
            .select_related("exact_location")
            .select_related("category")
        )
        for e in events:
            success = CategorisationRule.apply_rules(e)
            if success:
                nb += 1
                to_save.append(e)

        if nb != 0:
            Event.objects.bulk_update(to_save, fields=["category"])

        # set messages
        if nb != 0:
            if nb == 1:
                messages.success(
                    request,
                    _(
                        "The rules were successfully applied and 1 event with default category was categorised."
                    ),
                )
            else:
                messages.success(
                    request,
                    _(
                        "The rules were successfully applied and {} events with default category were categorised."
                    ).format(nb),
                )
        else:
            messages.info(
                request,
                _(
                    "The rules were successfully applied and no events were categorised."
                ),
            )

        if len(to_categorise) != 0:
            form = CategorisationForm(events=to_categorise)
            return render(
                request,
                "agenda_culturel/categorise_events_form.html",
                context={
                    "form": form,
                    "events": dict((e.pk, e) for e, c in to_categorise),
                    "categories": dict((e.pk, c) for e, c in to_categorise),
                },
            )
        else:
            return HttpResponseRedirect(reverse_lazy("categorisation_rules"))
