# -*- 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
"""

from apps.activities.models import Activity
from django.utils import timezone 
from django.db import transaction 
from django.contrib import messages
from django.http import JsonResponse 
from django.shortcuts import redirect
from django.views.generic import View, FormView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import login as auth_login, logout as auth_logout
from datetime import timedelta
from apps.authentication.forms import (
    LoginForm, UserRegistrationForm, PasswordResetRequestForm,
    PasswordResetConfirmForm
)
from apps.accounts.models import (
    User, UserSession,
    PasswordResetToken, Role, UserRole
)
from apps.common.utils import get_client_ip
from apps.activities.helpers import log_user_activity

class LoginView(FormView):
    """
    Enhanced login view with remember me functionality and security features.
    """
    template_name = "authentication/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
        Activity.log_activity(
            user=user,
            action="login",
            description=f"User {user.email if user else 'System'} performed login",
            request=self.request,
            ip_address=get_client_ip(self.request),
            user_agent=self.request.META.get("HTTP_USER_AGENT", ""),
            metadata={
                "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": get_client_ip(self.request),
                "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 and convert form errors to messages.
        """
        # Convert form errors to Django messages for SweetAlert display
        if form.non_field_errors():
            for error in form.non_field_errors():
                messages.error(self.request, str(error))
        
        # Convert field-specific errors to messages
        for field, errors in form.errors.items():
            if field != '__all__':  # Skip non-field errors (already handled above)
                field_name = form.fields[field].label or field.replace('_', ' ').title()
                for error in errors:
                    messages.error(self.request, f"{field_name}: {error}")
        
        # If no specific errors, add a general error message
        if not form.errors:
            messages.error(self.request, "Please check your input and try again.")
        
        # Log failed login attempt
        email = form.cleaned_data.get("email")
        if email:
            # TODO: Log failed login attempts separately without requiring user_id
            pass
        
        return super().form_invalid(form)


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
        Activity.log_activity(
            user=user,
            action="logout",
            description=f"User {user.email if user else 'System'} performed logout",
            request=request,
            ip_address=get_client_ip(request),
            user_agent=request.META.get("HTTP_USER_AGENT", ""),
            metadata={"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")


class RegisterView(FormView):
    """
    User registration view with profile creation.
    """
    template_name = "authentication/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
            Activity.log_activity(
                user=user,
                action="create",
                description=f"User {user.email if user else 'System'} performed create",
                request=self.request,
                object_type="User",
                object_id=str(user.id),
                object_repr=str(user),
                ip_address=get_client_ip(self.request),
                user_agent=self.request.META.get("HTTP_USER_AGENT", ""),
                metadata={
                    "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 form_invalid(self, form):
        """
        Handle failed registration and convert form errors to messages.
        """
        # Convert form errors to Django messages for SweetAlert display
        if form.non_field_errors():
            for error in form.non_field_errors():
                messages.error(self.request, str(error))
        
        # Convert field-specific errors to messages
        for field, errors in form.errors.items():
            if field != '__all__':  # Skip non-field errors (already handled above)
                field_name = form.fields[field].label or field.replace('_', ' ').title()
                for error in errors:
                    messages.error(self.request, f"{field_name}: {error}")
        
        return super().form_invalid(form)


class PasswordResetRequestView(FormView):
    """
    Password reset request view.
    """
    template_name = "authentication/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:
            Activity.log_activity(
                user=reset_token.user,
                action="admin",
                description=f"User {reset_token.user.email if reset_token.user else 'System'} performed admin",
                request=self.request,
                object_type="PasswordResetToken",
                object_id=str(reset_token.id),
                object_repr=str(reset_token),
                ip_address=get_client_ip(self.request),
                user_agent=self.request.META.get("HTTP_USER_AGENT", ""),
                metadata={"action": "password_reset_requested"}
            )
        
        return redirect("authentication:login")


class PasswordResetConfirmView(FormView):
    """
    Password reset confirmation view.
    """
    template_name = "authentication/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
            Activity.log_activity(
                user=user,
                action="update",
                description=f"User {user.email if user else 'System'} performed update",
                request=self.request,
                object_type="User",
                object_id=str(user.id),
                object_repr=str(user),
                ip_address=get_client_ip(self.request),
                user_agent=self.request.META.get("HTTP_USER_AGENT", ""),
                metadata={"action": "password_reset_completed"}
            )
        
        messages.success(
            self.request,
            "Password reset successfully! Please log in with your new password."
        )
        
        return redirect("authentication:login")


# API Views for AJAX functionality
class CheckEmailAvailabilityView(View):
    """
    Check if email is available for registration.
    """
    def get(self, request):
        """
        Check if email is available for registration.
        """
        try:
            # Get email from request
            email = request.GET.get("email", "").lower().strip()
            # Validate email
            if not email:
                # Return error if email is empty
                return JsonResponse({
                    "available": False, 
                    "error": "Email is required",
                    "status": "error"
                }, status=200)
            # Check if email exists
            exists = User.objects.filter(email=email).exists()
            # Return response
            return JsonResponse({
                "available": not exists,
                "email": email,
                "status": "success"
            }, status=200)
        except Exception as e:
            return JsonResponse({
                "available": False, 
                "error": str(e),
                "status": "error"
            }, status=200)
