from django.contrib.auth import views as auth_views
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy
from django.views import generic, View
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth import get_user_model
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from .forms import EmailAuthenticationForm, UserForm, RoleForm
from .models import User, UserRole as Role, Department
from .management_forms import MinisterUserForm

class LoginView(auth_views.LoginView):
    """
    Custom login view that uses email for authentication.
    """
    form_class = EmailAuthenticationForm
    template_name = 'registration/login.html'
    redirect_authenticated_user = True

    def get_success_url(self):
        # Redirect to the appropriate dashboard if the user is authenticated
        if self.request.user.is_authenticated:
            # If user is a superuser, redirect to custom admin dashboard
            if self.request.user.is_superuser:
                return reverse_lazy('admin_dashboard')
            # If the user has a role, redirect to their role-specific dashboard
            elif hasattr(self.request.user, 'role') and self.request.user.role:
                return reverse_lazy('dashboard')
            # For staff users without a specific role
            elif self.request.user.is_staff:
                return reverse_lazy('admin_dashboard')
        # Default fallback to home
        return reverse_lazy('home')

    def form_invalid(self, form):
        # Add a custom error message for invalid login
        error_message = 'Invalid email or password. Please try again.'
        if form.errors.get('__all__'):
            error_message = form.errors['__all__'][0]
        form.add_error(None, error_message)
        return super().form_invalid(form)


# User Views
class UserListView(LoginRequiredMixin, ListView):
    model = User
    template_name = 'users/user_list.html'
    context_object_name = 'users'
    paginate_by = 20

    def get_queryset(self):
        queryset = super().get_queryset()
        
        # Superusers can see all users
        if self.request.user.is_superuser:
            return queryset.select_related('role', 'department').order_by('-date_joined')
            
        # If user is not authenticated or has no role, don't show any users
        if not self.request.user.is_authenticated or not hasattr(self.request.user, 'role') or not self.request.user.role:
            return queryset.none()
            
        # Staff users can see all users in their department and below
        if self.request.user.is_staff:
            if hasattr(self.request.user, 'department') and self.request.user.department:
                # Get all departments under the user's department
                department_ids = [self.request.user.department.id]
                # If it's a ministry, get all its departments
                if hasattr(self.request.user.department, 'is_ministry') and self.request.user.department.is_ministry:
                    department_ids.extend(self.request.user.department.get_descendants().values_list('id', flat=True))
                return queryset.filter(department_id__in=department_ids).select_related('role', 'department').order_by('-date_joined')
            return queryset.none()
            
        # If user is a minister, show Director Generals and Heads of Sections in their ministry
        if self.request.user.role.name == 'minister':
            if not hasattr(self.request.user, 'department') or not self.request.user.department:
                return queryset.none()
                
            # Get all departments under the minister's ministry
            ministry_departments = self.request.user.department.get_descendants(include_self=False)
            # Get users who are either Director Generals or Heads of Sections in those departments
            return queryset.filter(
                role__name__in=['director', 'head'],
                department__in=ministry_departments
            ).select_related('role', 'department').order_by('-date_joined')
            
        # Default: show no users if user doesn't have appropriate permissions
        return queryset.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Add flag to control UI elements based on user role
        if (hasattr(self.request.user, 'role') and 
            self.request.user.role and 
            self.request.user.role.name == 'minister'):
            context['is_minister'] = True
        else:
            context['is_minister'] = False
        return context


class UserDetailView(LoginRequiredMixin, DetailView):
    model = User
    template_name = 'users/user_detail.html'
    context_object_name = 'user_detail'


class UserCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = User
    template_name = 'users/user_form.html'
    success_message = 'User was created successfully.'

    def get_form_class(self):
        # Check if user has a role and it has a name attribute
        if hasattr(self.request.user, 'role') and hasattr(self.request.user.role, 'name'):
            # Both ministers and directors can create heads of section
            if self.request.user.role.name in ['minister', 'director']:
                return MinisterUserForm
        # Default to UserForm if no role or not authorized
        return UserForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        # Pass request and role_type to the form for authorized users
        if hasattr(self.request.user, 'role') and hasattr(self.request.user.role, 'name'):
            if self.request.user.role.name in ['minister', 'director']:
                kwargs['request'] = self.request
                role_type = self.request.GET.get('role')
                # Directors can only create heads, ministers can create both directors and heads
                if (self.request.user.role.name == 'minister' and role_type in ['director', 'head']) or \
                   (self.request.user.role.name == 'director' and role_type == 'head'):
                    kwargs['role_type'] = role_type
        return kwargs

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Set page title based on role type
        if hasattr(self.request.user, 'role') and hasattr(self.request.user.role, 'name'):
            role_type = self.request.GET.get('role')
            if role_type == 'director' and self.request.user.role.name == 'minister':
                context['title'] = 'Add Director General'
            elif role_type == 'head' and self.request.user.role.name in ['minister', 'director']:
                context['title'] = 'Add Head of Section'
            else:
                context['title'] = 'Create User'
        else:
            context['title'] = 'Create User'
        return context

    def get_success_url(self):
        return reverse_lazy('users:user_detail', kwargs={'pk': self.object.pk})


class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = User
    form_class = UserForm
    template_name = 'users/user_form.html'
    success_message = 'User was updated successfully.'

    def get_success_url(self):
        return reverse_lazy('users:user_detail', kwargs={'pk': self.object.pk})


class UserDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
    model = User
    template_name = 'users/user_confirm_delete.html'
    success_url = reverse_lazy('users:user_list')
    success_message = 'User was deleted successfully.'

    def delete(self, request, *args, **kwargs):
        messages.success(self.request, self.success_message)
        return super().delete(request, *args, **kwargs)


# Role Views
class RoleListView(LoginRequiredMixin, ListView):
    model = Role
    template_name = 'users/role_list.html'
    context_object_name = 'roles'


class RoleDetailView(LoginRequiredMixin, DetailView):
    model = Role
    template_name = 'users/role_detail.html'
    context_object_name = 'role'


class RoleCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = Role
    form_class = RoleForm
    template_name = 'users/role_form.html'
    success_message = 'Role was created successfully.'

    def get_success_url(self):
        return reverse_lazy('users:role_detail', kwargs={'pk': self.object.pk})


class RoleUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Role
    form_class = RoleForm
    template_name = 'users/role_form.html'
    success_message = 'Role was updated successfully.'

    def get_success_url(self):
        return reverse_lazy('users:role_detail', kwargs={'pk': self.object.pk})


class RoleDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
    model = Role
    template_name = 'users/role_confirm_delete.html'
    success_url = reverse_lazy('users:role_list')
    success_message = 'Role was deleted successfully.'

    def delete(self, request, *args, **kwargs):
        messages.success(self.request, self.success_message)
        return super().delete(request, *args, **kwargs)


# Department Views
class DepartmentListView(LoginRequiredMixin, ListView):
    model = Department
    template_name = 'users/department_list.html'
    context_object_name = 'departments'


class DepartmentDetailView(LoginRequiredMixin, DetailView):
    model = Department
    template_name = 'users/department_detail.html'
    context_object_name = 'department'


class DepartmentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = Department
    fields = ['name', 'description', 'parent']
    template_name = 'users/department_form.html'
    success_message = 'Department was created successfully.'

    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        form.fields['parent'].queryset = Department.objects.exclude(id__in=self.get_descendant_ids())
        return form

    def get_descendant_ids(self, parent_id=None, ids=None):
        if ids is None:
            ids = []
        if parent_id:
            children = Department.objects.filter(parent_id=parent_id)
        else:
            children = Department.objects.filter(parent__isnull=True)
        for child in children:
            ids.append(child.id)
            self.get_descendant_ids(child.id, ids)
        return ids

    def get_success_url(self):
        return reverse_lazy('departments:department_detail', kwargs={'pk': self.object.pk})


class DepartmentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
    model = Department
    fields = ['name', 'description', 'parent']
    template_name = 'users/department_form.html'
    success_message = 'Department was updated successfully.'

    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        form.fields['parent'].queryset = Department.objects.exclude(
            id__in=self.get_descendant_ids(self.object.id) + [self.object.id]
        )
        return form

    def get_descendant_ids(self, parent_id, ids=None):
        if ids is None:
            ids = []
        children = Department.objects.filter(parent_id=parent_id)
        for child in children:
            ids.append(child.id)
            self.get_descendant_ids(child.id, ids)
        return ids

    def get_success_url(self):
        return reverse_lazy('departments:department_detail', kwargs={'pk': self.object.pk})


class DepartmentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
    model = Department
    template_name = 'users/department_confirm_delete.html'
    success_url = reverse_lazy('departments:department_list')
    success_message = 'Department was deleted successfully.'

    def delete(self, request, *args, **kwargs):
        messages.success(self.request, self.success_message)
        return super().delete(request, *args, **kwargs)
