# -*- coding: utf-8 -*-
"""
Authentification Views

This module contains class-based views for user authentication operations.
All views inherit from Django's generic class-based views for consistency
and maintainability.

Views:
    - LoginView: User login with email authentication
    - LogoutView: User logout
    - RegisterView: User registration with email verification
    - PasswordResetView: Password reset request
    - PasswordResetConfirmView: Password reset confirmation
    - EmailConfirmationView: Email address confirmation
    - ChangePasswordView: Password change for authenticated users

Author: AdTlas Development Team
Version: 1.0.0
Last Updated: 2024
"""

from django.contrib.auth import login, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import (
    LoginView as DjangoLoginView,
    LogoutView as DjangoLogoutView,
    PasswordResetView as DjangoPasswordResetView,
    PasswordResetConfirmView as DjangoPasswordResetConfirmView
)
from django.contrib.messages.views import SuccessMessageMixin
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, FormView, TemplateView
from django.contrib import messages
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.cache import never_cache

from apps.core.utils import send_email_notification
from .forms import (
    LoginForm,
    RegisterForm,
    PasswordResetForm,
    PasswordResetConfirmForm,
    ChangePasswordForm
)


class LoginView(SuccessMessageMixin, DjangoLoginView):
    """
    User login view with email-based authentication.
    
    This view handles user login using email instead of username.
    Supports both session-based and JWT authentication.
    
    Attributes:
        form_class: The form class to use for login
        template_name: Template for rendering the login form
        success_url: URL to redirect after successful login
        success_message: Message to display on successful login
    """
    
    form_class = LoginForm
    template_name = 'authentification/login.html'
    success_url = reverse_lazy('dashboard:home')
    success_message = _('Welcome back! You have been successfully logged in.')
    
    def dispatch(self, request, *args, **kwargs):
        """
        Handle the request dispatch.
        
        Redirects authenticated users to the dashboard.
        
        Args:
            request: The HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: The response object
        """
        if request.user.is_authenticated:
            return redirect(self.success_url)
        return super().dispatch(request, *args, **kwargs)
    
    def form_valid(self, form):
        """
        Handle valid form submission.
        
        Args:
            form: The validated form instance
            
        Returns:
            HttpResponse: The response object
        """
        user = form.get_user()
        login(self.request, user)
        
        # Set session expiry based on remember_me
        if not form.cleaned_data.get('remember_me'):
            self.request.session.set_expiry(0)  # Browser session
        
        # Log the login activity
        from apps.activities.models import Activity
        Activity.objects.create(
            user=user,
            action='login',
            description=f'User {user.email} logged in',
            ip_address=self.request.META.get('REMOTE_ADDR')
        )
        
        return super().form_valid(form)
    
    def get_context_data(self, **kwargs):
        """
        Add extra context to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Template context data
        """
        context = super().get_context_data(**kwargs)
        context.update({
            'title': _('Login'),
            'page_description': _('Sign in to your AdTlas account'),
        })
        return context


class LogoutView(DjangoLogoutView):
    """
    User logout view.
    
    This view handles user logout and redirects to the login page.
    
    Attributes:
        next_page: URL to redirect after logout
        template_name: Template for logout confirmation
    """
    
    next_page = reverse_lazy('authentification:login')
    template_name = 'authentification/logout.html'
    
    def dispatch(self, request, *args, **kwargs):
        """
        Handle the request dispatch and log the logout activity.
        
        Args:
            request: The HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: The response object
        """
        if request.user.is_authenticated:
            # Log the logout activity
            from apps.activities.models import Activity
            Activity.objects.create(
                user=request.user,
                action='logout',
                description=f'User {request.user.email} logged out',
                ip_address=request.META.get('REMOTE_ADDR')
            )
        
        messages.success(request, _('You have been successfully logged out.'))
        return super().dispatch(request, *args, **kwargs)


class RegisterView(SuccessMessageMixin, CreateView):
    """
    User registration view.
    
    This view handles user registration with email verification.
    
    Attributes:
        form_class: The form class to use for registration
        template_name: Template for rendering the registration form
        success_url: URL to redirect after successful registration
        success_message: Message to display on successful registration
    """
    
    form_class = RegisterForm
    template_name = 'authentification/register.html'
    success_url = reverse_lazy('authentification:login')
    success_message = _(
        'Registration successful! Please check your email to verify your account.'
    )
    
    def dispatch(self, request, *args, **kwargs):
        """
        Handle the request dispatch.
        
        Redirects authenticated users to the dashboard.
        
        Args:
            request: The HTTP request object
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: The response object
        """
        if request.user.is_authenticated:
            return redirect('dashboard:home')
        return super().dispatch(request, *args, **kwargs)
    
    def form_valid(self, form):
        """
        Handle valid form submission.
        
        Args:
            form: The validated form instance
            
        Returns:
            HttpResponse: The response object
        """
        user = form.save()
        
        # Send email verification
        self.send_verification_email(user)
        
        # Log the registration activity
        from apps.activities.models import Activity
        Activity.objects.create(
            user=user,
            action='register',
            description=f'User {user.email} registered',
            ip_address=self.request.META.get('REMOTE_ADDR')
        )
        
        return super().form_valid(form)
    
    def send_verification_email(self, user):
        """
        Send email verification to the user.
        
        Args:
            user: The user instance
        """
        # Generate verification token (simplified)
        from django.utils.crypto import get_random_string
        token = get_random_string(32)
        
        # Store token in user profile or cache
        # This is a simplified implementation
        
        # Send email
        send_email_notification(
            subject=_('Verify your AdTlas account'),
            message=_(
                'Please click the link below to verify your email address:\n'
                f'http://localhost:8000/auth/verify-email/{token}/'
            ),
            recipient_list=[user.email]
        )
    
    def get_context_data(self, **kwargs):
        """
        Add extra context to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Template context data
        """
        context = super().get_context_data(**kwargs)
        context.update({
            'title': _('Register'),
            'page_description': _('Create your AdTlas account'),
        })
        return context


class PasswordResetView(SuccessMessageMixin, DjangoPasswordResetView):
    """
    Password reset request view.
    
    This view handles password reset requests.
    
    Attributes:
        form_class: The form class to use for password reset
        template_name: Template for rendering the password reset form
        success_url: URL to redirect after successful request
        success_message: Message to display on successful request
        email_template_name: Template for the reset email
        subject_template_name: Template for the email subject
    """
    
    form_class = PasswordResetForm
    template_name = 'authentification/password_reset.html'
    success_url = reverse_lazy('authentification:password_reset_done')
    success_message = _(
        'Password reset instructions have been sent to your email.'
    )
    email_template_name = 'authentification/password_reset_email.html'
    subject_template_name = 'authentification/password_reset_subject.txt'
    
    def get_context_data(self, **kwargs):
        """
        Add extra context to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Template context data
        """
        context = super().get_context_data(**kwargs)
        context.update({
            'title': _('Reset Password'),
            'page_description': _('Enter your email to reset your password'),
        })
        return context


class PasswordResetConfirmView(SuccessMessageMixin, DjangoPasswordResetConfirmView):
    """
    Password reset confirmation view.
    
    This view handles the actual password reset with the token.
    
    Attributes:
        form_class: The form class to use for password reset confirmation
        template_name: Template for rendering the form
        success_url: URL to redirect after successful reset
        success_message: Message to display on successful reset
    """
    
    form_class = PasswordResetConfirmForm
    template_name = 'authentification/password_reset_confirm.html'
    success_url = reverse_lazy('authentification:login')
    success_message = _(
        'Your password has been reset successfully. You can now log in.'
    )
    
    def get_context_data(self, **kwargs):
        """
        Add extra context to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Template context data
        """
        context = super().get_context_data(**kwargs)
        context.update({
            'title': _('Set New Password'),
            'page_description': _('Enter your new password'),
        })
        return context


class EmailConfirmationView(TemplateView):
    """
    Email confirmation view.
    
    This view handles email address confirmation with tokens.
    
    Attributes:
        template_name: Template for rendering the confirmation page
    """
    
    template_name = 'authentification/email_confirm.html'
    
    def get(self, request, token, *args, **kwargs):
        """
        Handle GET request for email confirmation.
        
        Args:
            request: The HTTP request object
            token: The confirmation token
            *args: Variable length argument list
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            HttpResponse: The response object
        """
        # Validate token and activate user
        # This is a simplified implementation
        try:
            # Token validation logic would go here
            # For now, we'll assume the token is valid
            
            messages.success(
                request,
                _('Your email has been verified successfully!')
            )
            return redirect('authentification:login')
            
        except Exception:
            messages.error(
                request,
                _('Invalid or expired confirmation token.')
            )
            return super().get(request, *args, **kwargs)
    
    def get_context_data(self, **kwargs):
        """
        Add extra context to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Template context data
        """
        context = super().get_context_data(**kwargs)
        context.update({
            'title': _('Email Confirmation'),
            'page_description': _('Confirming your email address'),
        })
        return context


class ChangePasswordView(LoginRequiredMixin, SuccessMessageMixin, FormView):
    """
    Password change view for authenticated users.
    
    This view allows authenticated users to change their password.
    
    Attributes:
        form_class: The form class to use for password change
        template_name: Template for rendering the form
        success_url: URL to redirect after successful change
        success_message: Message to display on successful change
    """
    
    form_class = ChangePasswordForm
    template_name = 'authentification/change_password.html'
    success_url = reverse_lazy('dashboard:profile')
    success_message = _('Your password has been changed successfully.')
    
    def get_form_kwargs(self):
        """
        Return the keyword arguments for instantiating the form.
        
        Returns:
            dict: Form keyword arguments
        """
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs
    
    def form_valid(self, form):
        """
        Handle valid form submission.
        
        Args:
            form: The validated form instance
            
        Returns:
            HttpResponse: The response object
        """
        form.save()
        
        # Log the password change activity
        from apps.activities.models import Activity
        Activity.objects.create(
            user=self.request.user,
            action='password_change',
            description=f'User {self.request.user.email} changed password',
            ip_address=self.request.META.get('REMOTE_ADDR')
        )
        
        return super().form_valid(form)
    
    def get_context_data(self, **kwargs):
        """
        Add extra context to the template.
        
        Args:
            **kwargs: Arbitrary keyword arguments
            
        Returns:
            dict: Template context data
        """
        context = super().get_context_data(**kwargs)
        context.update({
            'title': _('Change Password'),
            'page_description': _('Update your account password'),
        })
        return context


# API Views for AJAX/JSON responses

@method_decorator(csrf_exempt, name='dispatch')
@method_decorator(never_cache, name='dispatch')
class LoginAPIView(LoginView):
    """
    API view for login that returns JSON responses.
    
    This view extends the regular LoginView to provide JSON responses
    for AJAX requests and mobile applications.
    """
    
    def form_valid(self, form):
        """
        Handle valid form submission with JSON response.
        
        Args:
            form: The validated form instance
            
        Returns:
            JsonResponse: JSON response with success status
        """
        user = form.get_user()
        login(self.request, user)
        
        return JsonResponse({
            'success': True,
            'message': str(self.success_message),
            'redirect_url': str(self.success_url)
        })
    
    def form_invalid(self, form):
        """
        Handle invalid form submission with JSON response.
        
        Args:
            form: The invalid form instance
            
        Returns:
            JsonResponse: JSON response with error details
        """
        return JsonResponse({
            'success': False,
            'errors': form.errors
        }, status=400)


@method_decorator(csrf_exempt, name='dispatch')
class RegisterAPIView(RegisterView):
    """
    API view for registration that returns JSON responses.
    
    This view extends the regular RegisterView to provide JSON responses
    for AJAX requests and mobile applications.
    """
    
    def form_valid(self, form):
        """
        Handle valid form submission with JSON response.
        
        Args:
            form: The validated form instance
            
        Returns:
            JsonResponse: JSON response with success status
        """
        user = form.save()
        self.send_verification_email(user)
        
        return JsonResponse({
            'success': True,
            'message': str(self.success_message),
            'user_id': user.id
        })
    
    def form_invalid(self, form):
        """
        Handle invalid form submission with JSON response.
        
        Args:
            form: The invalid form instance
            
        Returns:
            JsonResponse: JSON response with error details
        """
        return JsonResponse({
            'success': False,
            'errors': form.errors
        }, status=400)