import csv

from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import Permission
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import DeleteView, ListView, RedirectView, TemplateView

from bds.autocomplete import bds_search
from bds.forms import ProfileForm, UserForm, UserFromClipperForm, UserFromScratchForm
from bds.mixins import MultipleFormView, StaffRequiredMixin
from bds.models import BDSProfile
from shared.views import AutocompleteView

User = get_user_model()


class BDSAutocompleteView(StaffRequiredMixin, AutocompleteView):
    template_name = "bds/search_results.html"
    search_composer = bds_search


class Home(StaffRequiredMixin, TemplateView):
    template_name = "bds/home.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["member_count"] = BDSProfile.objects.filter(is_member=True).count()
        context["nb_expired"] = BDSProfile.expired_members().count()
        return context


class UserUpdateView(StaffRequiredMixin, MultipleFormView):
    template_name = "bds/user_update.html"

    form_classes = {
        "user": UserForm,
        "profile": ProfileForm,
    }

    def get_user_initial(self):
        return {"is_buro": self.get_user_instance().has_perm("bds.is_team")}

    def dispatch(self, request, *args, **kwargs):
        self.user = get_object_or_404(User, pk=self.kwargs["pk"])
        return super().dispatch(request, *args, **kwargs)

    def get_user_instance(self):
        return self.user

    def get_profile_instance(self):
        return getattr(self.user, "bds", None)

    def get_success_url(self):
        return reverse("bds:user.update", args=(self.user.pk,))

    def form_valid(self, forms):
        user = forms["user"].save()
        profile = forms["profile"].save(commit=False)
        perm = Permission.objects.get(content_type__app_label="bds", codename="is_team")
        if forms["user"].cleaned_data["is_buro"]:
            user.user_permissions.add(perm)
        else:
            user.user_permissions.remove(perm)
        profile.user = user
        profile.save()
        messages.success(self.request, _("Profil mis à jour avec succès !"))

        return super().form_valid(forms)

    def form_invalid(self, forms):
        messages.error(self.request, _("Veuillez corriger les erreurs ci-dessous"))
        return super().form_invalid(forms)


class UserCreateView(StaffRequiredMixin, MultipleFormView):
    template_name = "bds/user_create.html"

    def get_form_classes(self):
        profile_class = ProfileForm

        if "clipper" in self.kwargs:
            user_class = UserFromClipperForm
        else:
            user_class = UserFromScratchForm

        return {"user": user_class, "profile": profile_class}

    def get_user_initial(self):
        if "clipper" in self.kwargs:
            clipper = self.kwargs["clipper"]
            email = self.request.GET.get("mail", "{}@clipper.ens.fr".format(clipper))
            fullname = self.request.GET.get("fullname", None)

            if fullname:
                # Heuristique : le premier mot est le prénom
                first_name = fullname.split()[0]
                last_name = " ".join(fullname.split()[1:])
            else:
                first_name = ""
                last_name = ""

            return {
                "username": clipper,
                "email": email,
                "first_name": first_name,
                "last_name": last_name,
            }
        else:
            return {}

    def get_success_url(self):
        return reverse("bds:user.update", args=(self.user.pk,))

    def form_valid(self, forms):
        # On redéfinit self.user pour get_success_url
        self.user = forms["user"].save()
        profile = forms["profile"].save(commit=False)
        profile.user = self.user
        profile.save()
        messages.success(self.request, _("Profil créé avec succès !"))

        return super().form_valid(forms)

    def form_invalid(self, forms):
        messages.error(self.request, _("Veuillez corriger les erreurs ci-dessous"))
        return super().form_invalid(forms)


class UserDeleteView(StaffRequiredMixin, DeleteView):
    model = User
    success_url = reverse_lazy("bds:home")
    success_message = "Profil supprimé avec succès !"

    def delete(self, request, *args, **kwargs):
        # SuccessMessageMixin does not work with DeleteView, see :
        # https://code.djangoproject.com/ticket/21926
        messages.success(request, self.success_message)

        return super().delete(request, *args, **kwargs)


class ResetMembershipListView(StaffRequiredMixin, ListView):
    model = BDSProfile
    template_name = "bds/expired_members.html"

    def get_queryset(self):
        return BDSProfile.expired_members()


class ResetMembershipView(StaffRequiredMixin, RedirectView):
    url = reverse_lazy("bds:members.expired")

    def get(self, request, *args, **kwargs):
        qs = BDSProfile.expired_members()
        nb = qs.count()

        qs.update(cotisation_period="NO", is_member=False, mails_bds=False)

        messages.success(request, f"{nb} adhésions réinitialisées")

        return super().get(request, *args, **kwargs)


@permission_required("bds.is_team")
def export_members(request):
    response = HttpResponse(content_type="text/csv")
    response["Content-Disposition"] = "attachment; filename=membres_bds.csv"

    writer = csv.writer(response)
    for profile in BDSProfile.objects.filter(is_member=True).all():
        user = profile.user
        bits = [
            user.username,
            user.get_full_name(),
            user.email,
        ]
        writer.writerow([str(bit) for bit in bits])

    return response
