from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import (
    PermissionRequiredMixin,
)
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import (
    CreateView,
    DeleteView,
    UpdateView,
)
from ..forms import (
    TagForm,
    TagRenameForm,
)
from ..models import (
    Tag,
    RecurrentImport,
    Event,
    remove_accents,
)
from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy
from datetime import date
from .utils import get_event_qs
from django.db.models import F, Q
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.shortcuts import render
from django.contrib import messages
from django.http import (
    HttpResponseRedirect,
)
import emoji


class TagUpdateView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Tag
    permission_required = "agenda_culturel.change_tag"
    form_class = TagForm
    success_message = _("The tag has been successfully updated.")


class TagCreateView(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
    model = Tag
    permission_required = "agenda_culturel.add_tag"
    form_class = TagForm
    success_message = _("The tag has been successfully created.")

    def get_initial(self, *args, **kwargs):
        initial = super().get_initial(**kwargs)
        if "name" in self.request.GET:
            initial["name"] = self.request.GET.get("name")
        return initial

    def form_valid(self, form):
        Tag.clear_cache()
        return super().form_valid(form)


class TagDeleteView(PermissionRequiredMixin, DeleteView):
    model = Tag
    permission_required = "agenda_culturel.delete_tag"
    success_url = reverse_lazy("view_all_tags")


def view_tag_past(request, t):
    return view_tag(request, t, True)


def view_tag(request, t, past=False):
    now = date.today()

    qs = get_event_qs(request).filter(tags__contains=[t])

    if past:
        qs = qs.filter(start_day__lt=now).order_by("-start_day", "-start_time")
    else:
        qs = qs.filter(start_day__gte=now).order_by("start_day", "start_time")

    qs = qs.filter(
        Q(other_versions__isnull=True)
        | Q(other_versions__representative=F("pk"))
        | Q(other_versions__representative__isnull=True)
    )

    paginator = Paginator(qs, 10)
    page = request.GET.get("page")

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

    rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])

    tag = Tag.objects.filter(name=t).first()
    context = {
        "tag": t,
        "paginator_filter": response,
        "object": tag,
        "rimports": rimports,
        "past": past,
    }
    return render(request, "agenda_culturel/tag.html", context)


def tag_list(request):
    tags = Event.get_all_tags()
    r_tags = [t["tag"] for t in tags]
    objects = Tag.objects.order_by("name").all()
    d_objects = dict()
    for o in objects:
        d_objects[o.name] = o

    tags = [
        t | {"obj": d_objects[t["tag"]]} if t["tag"] in d_objects else t for t in tags
    ]
    tags += [
        {"obj": o, "tag": o.name, "count": 0} for o in objects if o.name not in r_tags
    ]

    context = {
        "tags": sorted(
            tags,
            key=lambda x: emoji.demojize(
                remove_accents(x["tag"]).lower(), delimiters=("000", "")
            ),
        )
    }
    return render(request, "agenda_culturel/tags.html", context)


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.change_tag")
def rename_tag(request, t):
    form = TagRenameForm(name=t)

    if request.method == "POST":
        form = TagRenameForm(request.POST, name=t)
        if form.is_valid():
            save = True
            if form.cleaned_data["name"] == t:
                messages.warning(
                    request,
                    _("You have not modified the tag name."),
                )
                save = False
            elif not form.is_force():
                if (
                    Event.objects.filter(
                        tags__contains=[form.cleaned_data["name"]]
                    ).count()
                    > 0
                ):
                    if Tag.objects.filter(name=form.cleaned_data["name"]):
                        messages.warning(
                            request,
                            (
                                _(
                                    "This tag {} is already in use, and is described by different information from the current tag. You can force renaming by checking the corresponding option. The information associated with tag {} will be deleted, and all events associated with tag {} will be associated with tag {}."
                                )
                            ).format(
                                form.cleaned_data["name"],
                                t,
                                t,
                                form.cleaned_data["name"],
                            ),
                        )
                    else:
                        messages.warning(
                            request,
                            (
                                _(
                                    "This tag {} is already in use. You can force renaming by checking the corresponding option."
                                )
                            ).format(form.cleaned_data["name"]),
                        )
                    save = False
                    form = TagRenameForm(request.POST, name=t, force=True)

            if save:
                # find all matching events and update them
                events = Event.objects.filter(tags__contains=[t])
                new_name = form.cleaned_data["name"]
                for e in events:
                    e.tags = [te for te in e.tags if te != t]
                    if new_name not in e.tags:
                        e.tags += [new_name]
                Event.objects.bulk_update(events, fields=["tags"])

                # find all recurrent imports and fix them
                rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
                for ri in rimports:
                    ri.defaultTags = [te for te in ri.defaultTags if te != t]
                    if new_name not in ri.tags:
                        ri.defaultTags += [new_name]
                RecurrentImport.objects.bulk_update(rimports, fields=["defaultTags"])

                # find tag object
                tag_object = Tag.objects.filter(name=t).first()
                if tag_object:
                    tag_object.name = new_name
                    tag_object.save()

                messages.success(
                    request,
                    (_("The tag {} has been successfully renamed to {}.")).format(
                        t, form.cleaned_data["name"]
                    ),
                )
                return HttpResponseRedirect(
                    reverse_lazy("view_tag", kwargs={"t": form.cleaned_data["name"]})
                )

    nb = Event.objects.filter(tags__contains=[t]).count()

    return render(
        request,
        "agenda_culturel/tag_rename_form.html",
        context={"form": form, "tag": t, "nb": nb},
    )


@login_required(login_url="/accounts/login/")
@permission_required("agenda_culturel.delete_tag")
def delete_tag(request, t):
    respage = reverse_lazy("view_all_tags")

    if request.method == "POST":
        # remove tag from events
        events = Event.objects.filter(tags__contains=[t])
        for e in events:
            e.tags = [te for te in e.tags if te != t]
        Event.objects.bulk_update(events, fields=["tags"])

        # remove tag from recurrent imports
        rimports = RecurrentImport.objects.filter(defaultTags__contains=[t])
        for ri in rimports:
            ri.tags = [te for te in ri.defaultTags if te != t]
        RecurrentImport.objects.bulk_update(rimports, fields=["defaultTags"])

        # find tag object
        tag_object = Tag.objects.filter(name=t).first()
        if tag_object:
            tag_object.delete()

        messages.success(
            request,
            (_("The tag {} has been successfully deleted.")).format(t),
        )
        return HttpResponseRedirect(respage)
    else:
        nb = Event.objects.filter(tags__contains=[t]).count()
        obj = Tag.objects.filter(name=t).first()
        nbi = RecurrentImport.objects.filter(defaultTags__contains=[t]).count()
        cancel_url = request.META.get("HTTP_REFERER", "")
        if cancel_url == "":
            cancel_url = respage
        return render(
            request,
            "agenda_culturel/tag_confirm_delete_by_name.html",
            {
                "tag": t,
                "nb": nb,
                "nbi": nbi,
                "cancel_url": cancel_url,
                "obj": obj,
            },
        )
