from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import PermissionDenied
from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect, render
from django.views import View
from django.views.generic import ListView

from apps.core.models import ActivityLog

from . import roles
from .forms import UserForm
from .services import actor_is_admin, user_role

User = get_user_model()


class UserListView(PermissionRequiredMixin, ListView):
    permission_required = "auth.view_user"
    template_name = "accounts/user_list.html"
    paginate_by = 25

    def get_queryset(self):
        qs = User.objects.prefetch_related("groups").order_by("username")
        q = self.request.GET.get("q", "").strip()
        if q:
            qs = qs.filter(Q(username__icontains=q) | Q(first_name__icontains=q) | Q(last_name__icontains=q) | Q(email__icontains=q))
        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        for u in ctx["object_list"]:
            u.role_label = roles.ROLE_LABELS.get(user_role(u), "بدون دور")
        return ctx


class UserEditView(PermissionRequiredMixin, View):
    template_name = "accounts/user_form.html"

    def get_permission_required(self):
        return ("auth.change_user",) if "pk" in self.kwargs else ("auth.add_user",)

    def get_target(self, request, pk):
        if pk is None:
            return None
        target = get_object_or_404(User, pk=pk)
        # Only administrators may touch administrator or superuser accounts.
        if (target.is_superuser or user_role(target) == roles.ADMINISTRATOR) and not actor_is_admin(request.user):
            raise PermissionDenied
        return target

    def get(self, request, pk=None):
        target = self.get_target(request, pk)
        return render(request, self.template_name, {"form": UserForm(instance=target, actor=request.user), "target": target})

    def post(self, request, pk=None):
        target = self.get_target(request, pk)
        before_role = user_role(target) if target else None
        form = UserForm(request.POST, instance=target, actor=request.user)
        if form.is_valid():
            changed = [f for f in form.changed_data if f not in ("password1", "password2")]
            password_changed = bool(form.cleaned_data.get("password1"))
            user = form.save()
            details = {"fields": changed, "password_changed": password_changed, "role_before": before_role,
                       "role_after": form.cleaned_data["role"]}
            ActivityLog.record(ActivityLog.PERMISSION, user=request.user, obj=user, request=request,
                               details={"created": target is None, **details})
            messages.success(request, "تم حفظ المستخدم.")
            return redirect("user_list")
        messages.error(request, "تعذّر الحفظ، راجع الحقول المعلَّمة.")
        return render(request, self.template_name, {"form": form, "target": target})
