# -*- coding: utf-8 -*-
"""
Accounts Views Module

This module contains views for user management, roles, and permissions
including user registration, profile management, role assignment,
and user administration.

Author: Senior Django Developer
Date: 2024
"""

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib import messages
from django.core.mail import send_mail
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.views.generic import (
    View, TemplateView, FormView, ListView, DetailView,
    CreateView, UpdateView, DeleteView
)
from django.http import (
    JsonResponse, HttpResponse, HttpResponseRedirect, Http404
)
from django.urls import reverse_lazy, reverse
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.db.models import Q, Count, Prefetch
from django.core.paginator import Paginator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.utils.decorators import method_decorator
from django.contrib.auth.forms import UserCreationForm
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView
from datetime import timedelta
import json
import logging

from .models import Role, User, Profile
from .forms import (
    UserRegistrationForm,
    ProfileForm,
    UserUpdateForm,
    RoleForm,
    UserRoleAssignmentForm
)
from .serializers import (
    UserSerializer,
    ProfileSerializer,
    RoleSerializer
)
from apps.authentication.utils import (
    get_client_ip,
    get_user_agent_info,
    log_security_event
)
from apps.authentication.models import EmailVerificationToken


# from django.views.generic import DetailView, FormView, UpdateView
# from django.urls import reverse_lazy

# from apps.accounts.forms import UserProfileExtendedForm, UserProfileForm, CustomPasswordChangeForm

# Get the custom user model
User = get_user_model()

# Set up logging
logger = logging.getLogger(__name__)


class UserRegistrationView(FormView):
    """
    User registration view with email verification.
    
    Features:
    - User account creation
    - Email verification token generation
    - Welcome email sending
    - Security logging
    """
    
    template_name = 'accounts/register.html'
    form_class = UserRegistrationForm
    success_url = reverse_lazy('accounts:registration_complete')
    
    def dispatch(self, request, *args, **kwargs):
        """
        Redirect authenticated users to dashboard.
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        """
        # Redirect authenticated users to dashboard
        if request.user.is_authenticated:
            return redirect('core:dashboard')
        return super().dispatch(request, *args, **kwargs)
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('Create Account')
        context['page_description'] = _('Join us today and get started')
        return context
    
    def form_valid(self, form):
        """
        Handle valid form submission.
        
        Args:
            form: Valid registration form
            
        Returns:
            HttpResponse: Response object
        """
        # Create user account
        user = form.save(commit=False)
        user.is_active = True  # Account is active but email not verified
        user.is_verified = False
        user.save()
        
        # Create email verification token
        verification_token = EmailVerificationToken.objects.create(
            user=user,
            requested_ip=get_client_ip(self.request)
        )
        
        # Send verification email
        self.send_verification_email(user, verification_token)
        
        # Log the registration
        log_security_event(
            'user_registration',
            user=user,
            ip_address=get_client_ip(self.request),
            details={
                'user_agent': self.request.META.get('HTTP_USER_AGENT', ''),
                'email': user.email
            }
        )
        
        # Success message
        messages.success(
            self.request,
            _('Account created successfully! Please check your email to verify your account.')
        )
        
        return super().form_valid(form)
    
    def send_verification_email(self, user, verification_token):
        """
        Send email verification email to user.
        
        Args:
            user: User instance
            verification_token: EmailVerificationToken instance
        """
        # Generate verification URL
        verification_url = self.request.build_absolute_uri(
            reverse('authentication:verify_email', kwargs={
                'token': verification_token.token
            })
        )
        
        # Render email template
        html_message = render_to_string(
            'accounts/emails/email_verification.html',
            {
                'user': user,
                'verification_url': verification_url,
                'site_name': getattr(settings, 'SITE_NAME', 'Our Site'),
                'expires_at': verification_token.expires_at
            }
        )
        
        plain_message = strip_tags(html_message)
        
        # Send email
        send_mail(
            subject=_('Verify Your Email Address'),
            message=plain_message,
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[user.email],
            html_message=html_message,
            fail_silently=False
        )


class ProfileView(LoginRequiredMixin, DetailView):
    """
    User profile view for displaying user information.
    
    Shows user details, profile information, and account statistics.
    """
    
    model = User
    template_name = 'accounts/profile.html'
    context_object_name = 'profile_user'
    
    def get_object(self, queryset=None):
        """
        Get the user object to display.
        
        Args:
            queryset: Optional queryset to use
            
        Returns:
            User: User instance
        """
        # Get user ID from URL or use current user
        user_id = self.kwargs.get('user_id')
        if user_id:
            # Check if current user can view other profiles
            if not (self.request.user.is_staff or 
                   self.request.user.has_perm('accounts.view_user')):
                raise Http404("You don't have permission to view this profile")
            return get_object_or_404(User, id=user_id)
        else:
            return self.request.user
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        user = self.get_object()
        
        context['title'] = _('User Profile')
        context['is_own_profile'] = user == self.request.user
        context['user_roles'] = user.roles.all()
        
        # Add profile statistics
        context['profile_stats'] = {
            'member_since': user.date_joined,
            'last_login': user.last_login,
            'total_roles': user.roles.count(),
            'is_verified': user.is_verified,
            'is_active': user.is_active
        }
        
        return context


class ProfileUpdateView(LoginRequiredMixin, UpdateView):
    """
    User profile update view for editing user information.
    
    Allows users to update their profile information and settings.
    """
    
    model = Profile
    form_class = ProfileForm
    template_name = 'accounts/profile_edit.html'
    
    def get_object(self, queryset=None):
        """
        Get the user profile object to edit.
        
        Args:
            queryset: Optional queryset to use
            
        Returns:
            Profile: Profile instance
        """
        return get_object_or_404(Profile, user=self.request.user)
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('Edit Profile')
        context['user_form'] = UserUpdateForm(instance=self.request.user)
        return context
    
    def form_valid(self, form):
        """
        Handle valid form submission.
        
        Args:
            form: Valid profile form
            
        Returns:
            HttpResponse: Response object
        """
        # Also handle user form if submitted
        user_form = UserUpdateForm(
            self.request.POST,
            instance=self.request.user
        )
        
        if user_form.is_valid():
            user_form.save()
        
        # Log the profile update
        log_security_event(
            'profile_update',
            user=self.request.user,
            ip_address=get_client_ip(self.request),
            details={
                'updated_fields': list(form.changed_data)
            }
        )
        
        messages.success(
            self.request,
            _('Profile updated successfully!')
        )
        
        return super().form_valid(form)
    
    def get_success_url(self):
        """
        Get the URL to redirect to after successful form submission.
        
        Returns:
            str: Success URL
        """
        return reverse('accounts:profile')


class UserListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
    """
    User list view for administrators.
    
    Displays a paginated list of all users with search and filtering.
    """
    
    model = User
    template_name = 'accounts/user_list.html'
    context_object_name = 'users'
    paginate_by = 20
    permission_required = 'accounts.view_user'
    
    def get_queryset(self):
        """
        Get the queryset of users to display.
        
        Returns:
            QuerySet: Filtered user queryset
        """
        queryset = User.objects.select_related('profile').prefetch_related('roles')
        
        # Search functionality
        search_query = self.request.GET.get('search', '')
        if search_query:
            queryset = queryset.filter(
                Q(email__icontains=search_query) |
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(profile__phone_number__icontains=search_query)
            )
        
        # Role filter
        role_filter = self.request.GET.get('role', '')
        if role_filter:
            queryset = queryset.filter(roles__id=role_filter)
        
        # Status filter
        status_filter = self.request.GET.get('status', '')
        if status_filter == 'active':
            queryset = queryset.filter(is_active=True)
        elif status_filter == 'inactive':
            queryset = queryset.filter(is_active=False)
        elif status_filter == 'verified':
            queryset = queryset.filter(is_verified=True)
        elif status_filter == 'unverified':
            queryset = queryset.filter(is_verified=False)
        
        # Ordering
        order_by = self.request.GET.get('order_by', '-date_joined')
        if order_by in ['email', '-email', 'first_name', '-first_name', 
                       'last_name', '-last_name', 'date_joined', '-date_joined',
                       'last_login', '-last_login']:
            queryset = queryset.order_by(order_by)
        
        return queryset
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('User Management')
        context['search_query'] = self.request.GET.get('search', '')
        context['current_role'] = self.request.GET.get('role', '')
        context['current_status'] = self.request.GET.get('status', '')
        context['current_order'] = self.request.GET.get('order_by', '-date_joined')
        context['available_roles'] = Role.objects.all()
        
        # Add statistics
        context['user_stats'] = {
            'total_users': User.objects.count(),
            'active_users': User.objects.filter(is_active=True).count(),
            'verified_users': User.objects.filter(is_verified=True).count(),
            'staff_users': User.objects.filter(is_staff=True).count()
        }
        
        return context


class RoleManagementView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
    """
    Role management view for administrators.
    
    Displays and manages user roles and permissions.
    """
    
    model = Role
    template_name = 'accounts/role_management.html'
    context_object_name = 'roles'
    permission_required = 'accounts.view_role'
    
    def get_queryset(self):
        """
        Get the queryset of roles to display.
        
        Returns:
            QuerySet: Role queryset with user counts
        """
        return Role.objects.annotate(
            user_count=Count('users')
        ).order_by('name')
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('Role Management')
        context['can_add_role'] = self.request.user.has_perm('accounts.add_role')
        context['can_change_role'] = self.request.user.has_perm('accounts.change_role')
        context['can_delete_role'] = self.request.user.has_perm('accounts.delete_role')
        return context


class UserRoleAssignmentView(LoginRequiredMixin, PermissionRequiredMixin, FormView):
    """
    User role assignment view for administrators.
    
    Allows administrators to assign or remove roles from users.
    """
    
    template_name = 'accounts/user_role_assignment.html'
    form_class = UserRoleAssignmentForm
    permission_required = 'accounts.change_user'
    
    def dispatch(self, request, *args, **kwargs):
        """
        Get the user object for role assignment.
        
        Args:
            request: HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: Response object
        """
        self.user_obj = get_object_or_404(User, id=kwargs['user_id'])
        return super().dispatch(request, *args, **kwargs)
    
    def get_form_kwargs(self):
        """
        Add user instance to form kwargs.
        
        Returns:
            dict: Form kwargs
        """
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.user_obj
        return kwargs
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('Assign Roles')
        context['target_user'] = self.user_obj
        context['current_roles'] = self.user_obj.roles.all()
        return context
    
    def form_valid(self, form):
        """
        Handle valid form submission.
        
        Args:
            form: Valid role assignment form
            
        Returns:
            HttpResponse: Response object
        """
        # Get selected roles
        selected_roles = form.cleaned_data['roles']
        
        # Get current roles for comparison
        current_roles = set(self.user_obj.roles.all())
        new_roles = set(selected_roles)
        
        # Calculate changes
        added_roles = new_roles - current_roles
        removed_roles = current_roles - new_roles
        
        # Update user roles
        self.user_obj.roles.set(selected_roles)
        
        # Log the role changes
        if added_roles or removed_roles:
            log_security_event(
                'role_assignment_change',
                user=self.request.user,
                ip_address=get_client_ip(self.request),
                details={
                    'target_user_id': self.user_obj.id,
                    'target_user_email': self.user_obj.email,
                    'added_roles': [role.name for role in added_roles],
                    'removed_roles': [role.name for role in removed_roles]
                }
            )
        
        messages.success(
            self.request,
            _('User roles updated successfully!')
        )
        
        return redirect('accounts:user_list')


@login_required
@permission_required('accounts.change_user', raise_exception=True)
def toggle_user_status(request, user_id):
    """
    Toggle user active status (activate/deactivate).
    
    Args:
        request: HTTP request object
        user_id: ID of the user to toggle
        
    Returns:
        HttpResponse: Response object
    """
    user = get_object_or_404(User, id=user_id)
    
    # Prevent self-deactivation
    if user == request.user:
        messages.error(
            request,
            _('You cannot deactivate your own account.')
        )
        return redirect('accounts:user_list')
    
    # Toggle status
    user.is_active = not user.is_active
    user.save(update_fields=['is_active'])
    
    # Log the status change
    log_security_event(
        'user_status_change',
        user=request.user,
        ip_address=get_client_ip(request),
        details={
            'target_user_id': user.id,
            'target_user_email': user.email,
            'new_status': 'active' if user.is_active else 'inactive'
        }
    )
    
    # Success message
    status_text = _('activated') if user.is_active else _('deactivated')
    messages.success(
        request,
        _(f'User {user.email} has been {status_text}.')
    )
    
    return redirect('accounts:user_list')


# API Views for REST API endpoints

class UserListAPIView(APIView):
    """
    API view for listing users.
    
    Provides REST API endpoint for user management.
    """
    
    permission_classes = [IsAuthenticated, IsAdminUser]
    
    def get(self, request):
        """
        Get list of users.
        
        Args:
            request: HTTP request object
            
        Returns:
            Response: API response with user list
        """
        users = User.objects.select_related('profile').prefetch_related('roles')
        
        # Apply search filter
        search = request.GET.get('search', '')
        if search:
            users = users.filter(
                Q(email__icontains=search) |
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search)
            )
        
        # Apply pagination
        page_size = min(int(request.GET.get('page_size', 20)), 100)
        page = int(request.GET.get('page', 1))
        
        paginator = Paginator(users, page_size)
        page_obj = paginator.get_page(page)
        
        # Serialize users
        serializer = UserSerializer(page_obj.object_list, many=True)
        
        return Response({
            'users': serializer.data,
            'pagination': {
                'current_page': page_obj.number,
                'total_pages': paginator.num_pages,
                'total_count': paginator.count,
                'has_next': page_obj.has_next(),
                'has_previous': page_obj.has_previous()
            }
        })


class UserDetailAPIView(APIView):
    """
    API view for user details.
    
    Provides REST API endpoint for individual user management.
    """
    
    permission_classes = [IsAuthenticated]
    
    def get(self, request, user_id):
        """
        Get user details.
        
        Args:
            request: HTTP request object
            user_id: ID of the user to retrieve
            
        Returns:
            Response: API response with user details
        """
        # Check permissions
        if user_id != request.user.id and not request.user.is_staff:
            return Response(
                {'error': 'Permission denied'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        try:
            user = User.objects.select_related('profile').prefetch_related('roles').get(id=user_id)
            serializer = UserSerializer(user)
            return Response(serializer.data)
        except User.DoesNotExist:
            return Response(
                {'error': 'User not found'},
                status=status.HTTP_404_NOT_FOUND
            )


@api_view(['GET'])
@permission_classes([IsAuthenticated, IsAdminUser])
def api_user_stats(request):
    """
    API endpoint for user statistics.
    
    Args:
        request: HTTP request object
        
    Returns:
        Response: API response with user statistics
    """
    stats = {
        'total_users': User.objects.count(),
        'active_users': User.objects.filter(is_active=True).count(),
        'verified_users': User.objects.filter(is_verified=True).count(),
        'staff_users': User.objects.filter(is_staff=True).count(),
        'recent_registrations': User.objects.filter(
            date_joined__gte=timezone.now() - timedelta(days=30)
        ).count(),
        'roles_count': Role.objects.count()
    }
    
    return Response(stats)


# Template Views

class RegistrationCompleteView(TemplateView):
    """
    Registration complete confirmation view.
    """
    template_name = 'accounts/registration_complete.html'
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('Registration Complete')
        return context


class AccountSettingsView(LoginRequiredMixin, TemplateView):
    """
    Account settings view for user preferences.
    """
    template_name = 'accounts/settings.html'
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Context data for template
        """
        context = super().get_context_data(**kwargs)
        context['title'] = _('Account Settings')
        context['user_profile'] = self.request.user.profile
        return context






# class ProfileView(LoginRequiredMixin, DetailView):
#     """User Profile View
    
#     This view displays the user's profile information. It requires the user to be authenticated.
#     """
    
#     model = get_user_model()
#     template_name = 'accounts/profile.html'
#     context_object_name = 'user'
#     login_url = 'login'

#     def get_object(self, queryset=None):
#         """Get the user object.
        
#         Returns:
#             User: The user object associated with the current session.
#         """
#         return self.request.user
    
#     def get_context_data(self, **kwargs):
#         """Get the context data for the view.
        
#         This method adds additional context data to the view, including the user's profile form.
        
#         Returns:
#             dict: A dictionary containing the context data.
#         """
#         context = super().get_context_data(**kwargs)
#         context['profile_form'] = UserProfileForm(instance=self.request.user)
#         return context
    
# class ProfileEditView(LoginRequiredMixin, UpdateView):
#     """User Profile Edit View
    
#     This view allows users to edit their profile information. It requires the user to be authenticated.
#     """
    
#     model = get_user_model()
#     form_class = UserProfileExtendedForm
#     template_name = 'accounts/profile_edit.html'
#     context_object_name = 'user'
#     login_url = 'login'
#     success_url = reverse_lazy('accounts:profile')
    
#     def get_object(self, queryset=None):
#         """Get the user object.
        
#         Returns:
#             User: The user object associated with the current session.
#         """
#         return self.request.user
    
#     def form_valid(self, form):
#         """Handle a valid form submission.
        
#         This method is called when the submitted form is valid. It saves the form data
#         to update the user's profile.
        
#         Args:
#             form (UserProfileExtendedForm): The validated form containing the user's profile data.
        
#         Returns:
#             HttpResponse: A redirect response to the success URL.
#         """
#         form.save()
#         return super().form_valid(form)
    
#     def get_context_data(self, **kwargs):
#         """Get the context data for the view.
        
#         This method adds additional context data to the view, including the user's profile form.
        
#         Returns:
#             dict: A dictionary containing the context data.
#         """
#         context = super().get_context_data(**kwargs)
#         context['profile_form'] = UserProfileForm(instance=self.request.user)
#         return context
    
# class PasswordChangeView(LoginRequiredMixin, FormView):
#     """User Password Change View
    
#     This view allows users to change their password. It requires the user to be authenticated.
#     """
    
#     form_class = CustomPasswordChangeForm
#     template_name = 'accounts/password_change.html'
#     context_object_name = 'user'
#     login_url = 'login'
#     success_url = reverse_lazy('accounts:profile')
    
#     def get_object(self, queryset=None):
#         """Get the user object.
        
#         Returns:
#             User: The user object associated with the current session.
#         """
#         return self.request.user
    
#     def form_valid(self, form):
#         """Handle a valid form submission.
        
#         This method is called when the submitted form is valid. It saves the form data
#         to update the user's password.
        
#         Args:
#             form (CustomPasswordChangeForm): The validated form containing the user's new password.
        
#         Returns:
#             HttpResponse: A redirect response to the success URL.
#         """
#         form.save()
#         return super().form_valid(form)
    
#     def get_context_data(self, **kwargs):
#         """Get the context data for the view.
        
#         This method adds additional context data to the view, including the user's password change form.
        
#         Returns:
#             dict: A dictionary containing the context data.
#         """
#         context = super().get_context_data(**kwargs)
#         context['password_change_form'] = CustomPasswordChangeForm(instance=self.request.user)
#         return context
    
#     def get_form_kwargs(self):
#         """Get keyword arguments for the form.
        
#         This method adds the current user to the form's keyword arguments.
        
#         Returns:
#             dict: A dictionary of keyword arguments for the form.
#         """
#         kwargs = super().get_form_kwargs()
#         kwargs['user'] = self.request.user
#         return kwargs


# # Utility Views

# def check_username_availability(request):
#     """Check if username is available (AJAX)."""
#     username = request.GET.get('username', '')
    
#     if not username:
#         return JsonResponse({'available': False, 'message': _('Username is required.')})
    
#     if username == request.user.username:
#         return JsonResponse({'available': True, 'message': _('Current username.')})
    
#     exists = User.objects.filter(username=username).exists()
    
#     return JsonResponse({
#         'available': not exists,
#         'message': _('Username is available.') if not exists else _('Username is already taken.')
#     })

# def check_email_availability(request):
#     """Check if email is available (AJAX)."""
#     email = request.GET.get('email', '')
    
#     if not email:
#         return JsonResponse({'available': False, 'message': _('Email is required.')})
    
#     if email.lower() == request.user.email.lower():
#         return JsonResponse({'available': True, 'message': _('Current email.')})
    
#     exists = User.objects.filter(email__iexact=email).exists()
    
#     return JsonResponse({
#         'available': not exists,
#         'message': _('Email is available.') if not exists else _('Email is already registered.')
#     })
