# -*- coding: utf-8 -*-
"""
Adtlas Authentication Views

Enhanced authentication views for the Adtlas DAI Management System.
Includes login, registration, password reset, and profile management.

Features:
    - Enhanced login with remember me functionality
    - User registration with email verification
    - Password reset with secure tokens
    - Profile management
    - Activity logging and session management

Author: Adtlas Development Team
Version: 2.0.0
Last Updated: 2025-07-09
"""

import uuid
from datetime import timedelta
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import JsonResponse, HttpResponse
from django.utils import timezone
from django.core.exceptions import ValidationError
from django.db import transaction
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.cache import never_cache
from django.contrib.auth.password_validation import validate_password
from django.core.paginator import Paginator
from django.db.models import Q
from django.conf import settings
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import View, TemplateView, FormView
from django.contrib.auth.mixins import LoginRequiredMixin

from .forms import (
    LoginForm, UserRegistrationForm, PasswordResetRequestForm,
    PasswordResetConfirmForm, ProfileForm
)
from apps.accounts.models import (
    User, Profile, UserSession, UserActivity, 
    PasswordResetToken, Role, UserRole
)


class LoginView(FormView):
    """
    Enhanced login view with remember me functionality and security features.
    """
    template_name = 'accounts/login.html'
    form_class = LoginForm
    
    def dispatch(self, request, *args, **kwargs):
        """
        Redirect authenticated users to dashboard.
        """
        if request.user.is_authenticated:
            return redirect('core:dashboard')
        return super().dispatch(request, *args, **kwargs)
    
    def get_form_kwargs(self):
        """
        Pass request to form for authentication.
        """
        kwargs = super().get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs
    
    def form_valid(self, form):
        """
        Handle successful login.
        """
        user = form.get_user()
        
        # Log the user in
        auth_login(self.request, user)
        
        # Handle remember me functionality
        if form.cleaned_data.get('remember_me'):
            # Set session to expire in 30 days
            self.request.session.set_expiry(30 * 24 * 60 * 60)
        else:
            # Set session to expire when browser is closed
            self.request.session.set_expiry(0)
        
        # Update user last login and activity
        user.last_login = timezone.now()
        user.last_activity = timezone.now()
        user.save(update_fields=['last_login', 'last_activity'])
        
        # Log user activity
        UserActivity.objects.create(
            user=user,
            action='login',
            ip_address=self.get_client_ip(),
            user_agent=self.request.META.get('HTTP_USER_AGENT', ''),
            details={
                'remember_me': form.cleaned_data.get('remember_me', False),
                'login_method': 'email_password'
            }
        )
        
        # Create or update user session
        UserSession.objects.update_or_create(
            user=user,
            session_key=self.request.session.session_key,
            defaults={
                'ip_address': self.get_client_ip(),
                'user_agent': self.request.META.get('HTTP_USER_AGENT', ''),
                'last_activity': timezone.now(),
                'expires_at': timezone.now() + timedelta(days=30 if form.cleaned_data.get('remember_me') else 1),
                'is_active': True
            }
        )
        
        # Success message
        messages.success(
            self.request,
            f'Welcome back, {user.get_short_name()}!'
        )
        
        # Redirect to next URL or dashboard
        next_url = self.request.GET.get('next') or self.request.POST.get('next')
        if next_url:
            return redirect(next_url)
        return redirect('core:dashboard')
    
    def form_invalid(self, form):
        """
        Handle failed login attempt.
        """
        # Log failed login attempt
        email = form.cleaned_data.get('email')
        if email:
            UserActivity.objects.create(
                user=None,
                action='login',
                ip_address=self.get_client_ip(),
                user_agent=self.request.META.get('HTTP_USER_AGENT', ''),
                details={
                    'email': email,
                    'status': 'failed',
                    'error': 'Invalid credentials'
                }
            )
        
        return super().form_invalid(form)
    
    def get_client_ip(self):
        """
        Get client IP address.
        """
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR')
        return ip


class LogoutView(LoginRequiredMixin, View):
    """
    Enhanced logout view with session cleanup.
    """
    
    def get(self, request):
        """
        Handle logout request.
        """
        return self.post(request)
    
    def post(self, request):
        """
        Handle logout and cleanup.
        """
        user = request.user
        
        # Log user activity
        UserActivity.objects.create(
            user=user,
            action='logout',
            ip_address=self.get_client_ip(),
            user_agent=request.META.get('HTTP_USER_AGENT', ''),
            details={'logout_method': 'user_initiated'}
        )
        
        # Deactivate user session
        try:
            user_session = UserSession.objects.get(
                user=user,
                session_key=request.session.session_key,
                is_active=True
            )
            user_session.is_active = False
            user_session.save()
        except UserSession.DoesNotExist:
            pass
        
        # Logout user
        auth_logout(request)
        
        messages.success(request, 'You have been successfully logged out.')
        return redirect('authentication:login')
    
    def get_client_ip(self):
        """
        Get client IP address.
        """
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR')
        return ip


class RegisterView(FormView):
    """
    User registration view with profile creation.
    """
    template_name = 'accounts/register.html'
    form_class = UserRegistrationForm
    
    def dispatch(self, request, *args, **kwargs):
        """
        Redirect authenticated users to dashboard.
        """
        if request.user.is_authenticated:
            return redirect('core:dashboard')
        return super().dispatch(request, *args, **kwargs)
    
    def form_valid(self, form):
        """
        Handle successful registration.
        """
        with transaction.atomic():
            user = form.save()
            
            # Assign default role if available
            try:
                default_role = Role.objects.get(is_default=True, is_active=True)
                UserRole.objects.create(
                    user=user,
                    role=default_role,
                    assigned_by=None,  # System assignment
                    notes='Default role assigned during registration'
                )
            except Role.DoesNotExist:
                pass
            
            # Log user activity
            UserActivity.objects.create(
                user=user,
                action='create',
                object_type='User',
                object_id=str(user.id),
                object_repr=str(user),
                ip_address=self.get_client_ip(),
                user_agent=self.request.META.get('HTTP_USER_AGENT', ''),
                details={
                    'registration_method': 'email_form',
                    'email_verified': user.is_verified
                }
            )
        
        messages.success(
            self.request,
            'Account created successfully! Please check your email to verify your account.'
        )
        
        # TODO: Send verification email
        
        return redirect('authentication:login')
    
    def get_client_ip(self):
        """
        Get client IP address.
        """
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR')
        return ip


class PasswordResetRequestView(FormView):
    """
    Password reset request view.
    """
    template_name = 'accounts/password_reset_request.html'
    form_class = PasswordResetRequestForm
    
    def form_valid(self, form):
        """
        Handle password reset request.
        """
        reset_token = form.save()
        
        # Always show success message for security
        messages.success(
            self.request,
            'If the email address exists in our system, you will receive '
            'password reset instructions shortly.'
        )
        
        # Log password reset request
        if reset_token:
            UserActivity.objects.create(
                user=reset_token.user,
                action='admin',
                object_type='PasswordResetToken',
                object_id=str(reset_token.id),
                object_repr=str(reset_token),
                ip_address=self.get_client_ip(),
                user_agent=self.request.META.get('HTTP_USER_AGENT', ''),
                details={'action': 'password_reset_requested'}
            )
        
        return redirect('authentication:login')
    
    def get_client_ip(self):
        """
        Get client IP address.
        """
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR')
        return ip


class PasswordResetConfirmView(FormView):
    """
    Password reset confirmation view.
    """
    template_name = 'accounts/password_reset_confirm.html'
    form_class = PasswordResetConfirmForm
    
    def dispatch(self, request, *args, **kwargs):
        """
        Validate reset token before showing form.
        """
        self.token = kwargs.get('token')
        
        try:
            self.reset_token = PasswordResetToken.objects.get(
                token=self.token,
                is_used=False
            )
            
            if self.reset_token.is_expired():
                messages.error(request, 'Password reset link has expired. Please request a new one.')
                return redirect('authentication:password_reset_request')
            
            self.user = self.reset_token.user
            
        except PasswordResetToken.DoesNotExist:
            messages.error(request, 'Invalid password reset link. Please request a new one.')
            return redirect('authentication:password_reset_request')
        
        return super().dispatch(request, *args, **kwargs)
    
    def get_form_kwargs(self):
        """
        Pass user to form.
        """
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.user
        return kwargs
    
    def form_valid(self, form):
        """
        Handle successful password reset.
        """
        with transaction.atomic():
            # Save new password
            user = form.save()
            
            # Mark token as used
            self.reset_token.is_used = True
            self.reset_token.save()
            
            # Log password reset
            UserActivity.objects.create(
                user=user,
                action='update',
                object_type='User',
                object_id=str(user.id),
                object_repr=str(user),
                ip_address=self.get_client_ip(),
                user_agent=self.request.META.get('HTTP_USER_AGENT', ''),
                details={'action': 'password_reset_completed'}
            )
        
        messages.success(
            self.request,
            'Password reset successfully! Please log in with your new password.'
        )
        
        return redirect('authentication:login')
    
    def get_client_ip(self):
        """
        Get client IP address.
        """
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR')
        return ip


class ProfileView(LoginRequiredMixin, View):
    """
    User profile view and management.
    """
    template_name = 'accounts/profile.html'
    
    def get(self, request):
        """
        Display user profile.
        """
        # Get or create user profile
        profile, created = Profile.objects.get_or_create(user=request.user)
        
        # Initialize form with current data
        form = ProfileForm(instance=profile, user=request.user)
        
        # Get user roles
        user_roles = UserRole.objects.filter(
            user=request.user,
            is_active=True
        ).select_related('role')
        
        # Get recent activities
        recent_activities = UserActivity.objects.filter(
            user=request.user
        ).order_by('-created_at')[:10]
        
        # Get active sessions
        active_sessions = UserSession.objects.filter(
            user=request.user,
            is_active=True
        ).order_by('-last_activity')
        
        context = {
            'form': form,
            'profile': profile,
            'user_roles': user_roles,
            'recent_activities': recent_activities,
            'active_sessions': active_sessions,
        }
        
        return render(request, self.template_name, context)
    
    def post(self, request):
        """
        Handle profile update.
        """
        profile, created = Profile.objects.get_or_create(user=request.user)
        form = ProfileForm(request.POST, request.FILES, instance=profile, user=request.user)
        
        if form.is_valid():
            with transaction.atomic():
                form.save()
                
                # Log profile update
                UserActivity.objects.create(
                    user=request.user,
                    action='update',
                    object_type='Profile',
                    object_id=str(profile.id),
                    object_repr=str(profile),
                    ip_address=self.get_client_ip(),
                    user_agent=request.META.get('HTTP_USER_AGENT', ''),
                    details={'updated_fields': list(form.changed_data)}
                )
            
            messages.success(request, 'Profile updated successfully!')
            return redirect('authentication:profile')
        
        # Re-render form with errors
        user_roles = UserRole.objects.filter(
            user=request.user,
            is_active=True
        ).select_related('role')
        
        recent_activities = UserActivity.objects.filter(
            user=request.user
        ).order_by('-created_at')[:10]
        
        active_sessions = UserSession.objects.filter(
            user=request.user,
            is_active=True
        ).order_by('-last_activity')
        
        context = {
            'form': form,
            'profile': profile,
            'user_roles': user_roles,
            'recent_activities': recent_activities,
            'active_sessions': active_sessions,
        }
        
        return render(request, self.template_name, context)
    
    def get_client_ip(self):
        """
        Get client IP address.
        """
        x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = self.request.META.get('REMOTE_ADDR')
        return ip


# Function-based views for backward compatibility
login_view = LoginView.as_view()
logout_view = LogoutView.as_view()
register_view = RegisterView.as_view()
password_reset_request_view = PasswordResetRequestView.as_view()
password_reset_confirm_view = PasswordResetConfirmView.as_view()
profile_view = ProfileView.as_view()


# API Views for AJAX functionality

@login_required
def check_email_availability(request):
    """
    Check if email is available for registration.
    """
    email = request.GET.get('email', '').lower().strip()
    
    if not email:
        return JsonResponse({'available': False, 'error': 'Email is required'})
    
    # Check if email exists
    exists = User.objects.filter(email=email).exists()
    
    return JsonResponse({
        'available': not exists,
        'email': email
    })


@login_required
def terminate_session(request, session_id):
    """
    Terminate a specific user session.
    """
    if request.method != 'POST':
        return JsonResponse({'error': 'Method not allowed'}, status=405)
    
    try:
        session = UserSession.objects.get(
            id=session_id,
            user=request.user,
            is_active=True
        )
        
        # Don't allow terminating current session
        if session.session_key == request.session.session_key:
            return JsonResponse({
                'success': False,
                'error': 'Cannot terminate current session'
            })
        
        # Deactivate session
        session.is_active = False
        session.save()
        
        # Log activity
        UserActivity.objects.create(
            user=request.user,
            action='admin',
            object_type='UserSession',
            object_id=str(session.id),
            object_repr=str(session),
            details={'action': 'session_terminated'}
        )
        
        return JsonResponse({'success': True})
        
    except UserSession.DoesNotExist:
        return JsonResponse({
            'success': False,
            'error': 'Session not found'
        })


@login_required
def user_activities_api(request):
    """
    API endpoint for user activities with pagination.
    """
    activities = UserActivity.objects.filter(
        user=request.user
    ).order_by('-created_at')
    
    # Apply filters
    action_filter = request.GET.get('action')
    if action_filter:
        activities = activities.filter(action=action_filter)
    
    # Pagination
    page = int(request.GET.get('page', 1))
    per_page = int(request.GET.get('per_page', 10))
    
    paginator = Paginator(activities, per_page)
    page_obj = paginator.get_page(page)
    
    # Serialize activities
    activities_data = []
    for activity in page_obj:
        activities_data.append({
            'id': activity.id,
            'action': activity.action,
            'object_type': activity.object_type,
            'object_repr': activity.object_repr,
            'created_at': activity.created_at.isoformat(),
            'details': activity.details
        })
    
    return JsonResponse({
        'activities': activities_data,
        'pagination': {
            'page': page_obj.number,
            'pages': paginator.num_pages,
            'per_page': per_page,
            'total': paginator.count
        }
    })
