from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required, user_passes_test
from django.db import transaction
from django.db.models import Q
from django.http import (
    HttpResponseBadRequest,
    HttpResponseRedirect,
    JsonResponse,
)
from django.shortcuts import get_object_or_404, render
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_http_methods
from django.views.generic import DetailView, ListView, UpdateView

from teamvault.apps.secrets.enums import SecretStatus
from .forms import UserProfileForm
from .models import UserProfile as UserProfileModel
from ..audit.auditlog import log
from ..audit.models import AuditLogCategoryChoices
from ..secrets.models import SecretRevision

User = get_user_model()


class UserProfile(UpdateView):
    form_class = UserProfileForm
    model = UserProfileModel
    template_name = 'accounts/user_settings.html'
    success_url = reverse_lazy('accounts.user-settings')

    def get_object(self, *args, **kwargs):  # noqa: ARG002
        return UserProfileModel.objects.get_or_create(user=self.request.user)[0]

    def form_valid(self, form):
        response = super().form_valid(form)
        messages.success(self.request, _('Successfully updated settings.'))
        return response


user_settings = login_required(UserProfile.as_view())


class UserList(ListView):
    context_object_name = 'users'
    model = User
    paginate_by = 25
    template_name = 'accounts/user_list.html'

    def get_queryset(self):
        return self.model.objects.order_by('username')


users = user_passes_test(lambda u: u.is_superuser)(UserList.as_view())


class UserDetail(DetailView):
    context_object_name = 'user'
    model = User
    slug_field = 'username'
    slug_url_kwarg = 'username'
    template_name = 'accounts/user_detail.html'


user_detail = user_passes_test(lambda u: u.is_superuser)(UserDetail.as_view())


@user_passes_test(lambda u: u.is_superuser)
def user_detail_from_request(request):
    username = request.GET.get('username', '').strip()
    if not username:
        return HttpResponseBadRequest(_('Username is required'))
    user = get_object_or_404(User, username=username)
    return HttpResponseRedirect(reverse('accounts.user-detail', kwargs={'username': user}))


@user_passes_test(lambda u: u.is_superuser)
@require_http_methods(['POST'])
def user_activate(request, username, deactivate=False):
    user = get_object_or_404(
        User,
        username=username,
        is_active=deactivate,
    )
    user.is_active = not deactivate
    user.save()
    if deactivate:
        user.groups.clear()
        accessed_revs = (
            SecretRevision.objects
            .filter(
                accessed_by=user,
            )
            .exclude(
                secret__needs_changing_on_leave=False,
            )
            .exclude(secret__status=SecretStatus.NEEDS_CHANGING)
            .select_related(
                'secret',
            )
        )
        secrets = set()
        for rev in accessed_revs:
            if rev.is_current_revision:
                secrets.add(rev.secret)
        with transaction.atomic():
            for secret in secrets:
                secret.status = SecretStatus.NEEDS_CHANGING
                secret.save()
                msg = _("secret '{secret}' needs changing because user '{user}' was deactivated").format(
                    secret=secret.name,
                    user=user.username,
                )
                log(
                    msg,
                    actor=request.user,
                    category=AuditLogCategoryChoices.USER_DEACTIVATED,
                    secret=secret,
                    user=user,
                )
        log(
            _('{actor} deactivated {user}, {secrets} secrets marked for changing').format(
                actor=request.user.username,
                user=user.username,
                secrets=len(secrets),
            ),
            actor=request.user,
            category=AuditLogCategoryChoices.USER_DEACTIVATED,
            user=user,
        )
    else:
        log(
            _('{actor} reactivated {user}').format(
                actor=request.user.username,
                user=user.username,
            ),
            actor=request.user,
            category=AuditLogCategoryChoices.USER_ACTIVATED,
            user=user,
        )
    return HttpResponseRedirect(reverse('accounts.user-detail', kwargs={'username': user.username}))


def search_user(request):
    if not request.user.is_superuser:
        return {}
    q = request.GET.get('q', '').strip()
    if not q:
        return {}
    users_queryset = User.objects.filter(
        Q(username__icontains=q) | Q(first_name__icontains=q) | Q(last_name__icontains=q)
    )[:15]
    results: list[dict[str, str]] = [
        {
            'username': user.username,
            'cn': f'{user.first_name} {user.last_name}'.strip(),
        }
        for user in users_queryset
    ]
    return JsonResponse({'results': results})


def get_user_avatar_partial(request):
    if not request.user.is_superuser:
        return {}
    username = request.GET.get('username', '').strip()
    if not username:
        return {}
    user = User.objects.get(username=username)
    return render(request, 'accounts/_avatar.html', {'user': user, 'tooltip_title': username})
