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

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

Features:
    - Enhanced login form with remember me functionality
    - User registration with profile creation
    - Password reset with secure token system
    - Profile management forms
    - Form validation and security measures

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

from django import forms
from django.contrib.auth import authenticate
from django.contrib.auth.forms import UserCreationForm, PasswordResetForm
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from datetime import timedelta
import re

from apps.accounts.models import User, Profile, PasswordResetToken


class LoginForm(forms.Form):
    """
    Enhanced login form with remember me functionality and security features.
    """
    
    email = forms.EmailField(
        max_length=254,
        widget=forms.EmailInput(attrs={
            'class': 'input100',
            'placeholder': 'Email Address',
            'required': True,
            'autofocus': True,
        }),
        label=_('Email Address'),
        help_text=_('Enter your registered email address')
    )
    
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'input100',
            'placeholder': 'Password',
            'required': True,
        }),
        label=_('Password'),
        help_text=_('Enter your password')
    )
    
    remember_me = forms.BooleanField(
        required=False,
        initial=False,
        widget=forms.CheckboxInput(attrs={
            'class': 'form-check-input',
            'id': 'remember-me'
        }),
        label=_('Remember me'),
        help_text=_('Keep me logged in for 30 days')
    )
    
    def __init__(self, request=None, *args, **kwargs):
        """
        Initialize the form with request context for authentication.
        """
        self.request = request
        self.user_cache = None
        super().__init__(*args, **kwargs)
    
    def clean(self):
        """
        Validate login credentials and check account status.
        """
        cleaned_data = super().clean()
        email = cleaned_data.get('email')
        password = cleaned_data.get('password')
        
        if email and password:
            # Normalize email
            email = email.lower().strip()
            
            try:
                user = User.objects.get(email=email)
                
                # Check if account is locked
                if user.is_account_locked():
                    raise ValidationError(
                        _('Account is temporarily locked due to multiple failed login attempts. '
                          'Please try again later or contact support.'),
                        code='account_locked'
                    )
                
                # Check if account is active
                if not user.is_active:
                    raise ValidationError(
                        _('Your account has been deactivated. Please contact support.'),
                        code='account_inactive'
                    )
                
                # Check if email is verified
                if not user.is_verified:
                    raise ValidationError(
                        _('Please verify your email address before logging in. '
                          'Check your inbox for the verification link.'),
                        code='email_not_verified'
                    )
                
                # Authenticate user
                self.user_cache = authenticate(
                    self.request,
                    username=email,
                    password=password
                )
                
                if self.user_cache is None:
                    # Increment failed login attempts
                    user.failed_login_attempts += 1
                    
                    # Lock account after 5 failed attempts
                    if user.failed_login_attempts >= 5:
                        user.account_locked_until = timezone.now() + timedelta(minutes=30)
                    
                    user.save(update_fields=['failed_login_attempts', 'account_locked_until'])
                    
                    raise ValidationError(
                        _('Invalid email or password. Please try again.'),
                        code='invalid_credentials'
                    )
                else:
                    # Reset failed login attempts on successful login
                    if user.failed_login_attempts > 0:
                        user.failed_login_attempts = 0
                        user.account_locked_until = None
                        user.save(update_fields=['failed_login_attempts', 'account_locked_until'])
                
            except User.DoesNotExist:
                # Don't reveal whether email exists
                raise ValidationError(
                    _('Invalid email or password. Please try again.'),
                    code='invalid_credentials'
                )
        
        return cleaned_data
    
    def get_user(self):
        """
        Return the authenticated user.
        """
        return self.user_cache


class UserRegistrationForm(UserCreationForm):
    """
    Enhanced user registration form with profile creation.
    """
    
    email = forms.EmailField(
        max_length=254,
        widget=forms.EmailInput(attrs={
            'class': 'input100',
            'placeholder': 'Email Address',
            'required': True,
        }),
        label=_('Email Address'),
        help_text=_('Enter a valid email address')
    )
    
    first_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(attrs={
            'class': 'input100',
            'placeholder': 'First Name',
            'required': True,
        }),
        label=_('First Name'),
        help_text=_('Enter your first name')
    )
    
    last_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(attrs={
            'class': 'input100',
            'placeholder': 'Last Name',
            'required': True,
        }),
        label=_('Last Name'),
        help_text=_('Enter your last name')
    )
    
    password1 = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'input100',
            'placeholder': 'Password',
            'required': True,
        }),
        label=_('Password'),
        help_text=_('Enter a strong password')
    )
    
    password2 = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'input100',
            'placeholder': 'Confirm Password',
            'required': True,
        }),
        label=_('Confirm Password'),
        help_text=_('Re-enter your password')
    )
    
    phone_number = forms.CharField(
        max_length=17,
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'input100',
            'placeholder': 'Phone Number (Optional)',
        }),
        label=_('Phone Number'),
        help_text=_('Enter your phone number (optional)')
    )
    
    job_title = forms.CharField(
        max_length=100,
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'input100',
            'placeholder': 'Job Title (Optional)',
        }),
        label=_('Job Title'),
        help_text=_('Enter your job title (optional)')
    )
    
    company = forms.CharField(
        max_length=100,
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'input100',
            'placeholder': 'Company (Optional)',
        }),
        label=_('Company'),
        help_text=_('Enter your company name (optional)')
    )
    
    terms_accepted = forms.BooleanField(
        required=True,
        widget=forms.CheckboxInput(attrs={
            'class': 'form-check-input',
        }),
        label=_('I agree to the Terms of Service and Privacy Policy'),
        error_messages={
            'required': _('You must accept the terms and conditions to register.')
        }
    )
    
    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name', 'password1', 'password2')
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Remove username field since we use email
        if 'username' in self.fields:
            del self.fields['username']
    
    def clean_email(self):
        """
        Validate email uniqueness and format.
        """
        email = self.cleaned_data.get('email')
        if email:
            email = email.lower().strip()
            
            # Check if email already exists
            if User.objects.filter(email=email).exists():
                raise ValidationError(
                    _('An account with this email address already exists.'),
                    code='email_exists'
                )
            
            # Additional email validation
            if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
                raise ValidationError(
                    _('Please enter a valid email address.'),
                    code='invalid_email'
                )
        
        return email
    
    def clean_phone_number(self):
        """
        Validate phone number format if provided.
        """
        phone = self.cleaned_data.get('phone_number')
        if phone:
            # Remove all non-digit characters
            phone = re.sub(r'[^\d+]', '', phone)
            
            # Basic phone number validation
            if not re.match(r'^\+?1?\d{9,15}$', phone):
                raise ValidationError(
                    _('Please enter a valid phone number.'),
                    code='invalid_phone'
                )
        
        return phone
    
    def save(self, commit=True):
        """
        Save user and create associated profile.
        """
        user = super().save(commit=False)
        user.email = self.cleaned_data['email'].lower().strip()
        user.username = user.email  # Use email as username
        user.is_verified = False  # Will be verified via email
        
        if commit:
            user.save()
            
            # Create user profile
            Profile.objects.create(
                user=user,
                phone_number=self.cleaned_data.get('phone_number', ''),
                job_title=self.cleaned_data.get('job_title', ''),
                company=self.cleaned_data.get('company', ''),
            )
            
            # TODO: Send verification email
            
        return user


class PasswordResetRequestForm(forms.Form):
    """
    Form for requesting password reset.
    """
    
    email = forms.EmailField(
        max_length=254,
        widget=forms.EmailInput(attrs={
            'class': 'input100',
            'placeholder': 'Email Address',
            'required': True,
            'autofocus': True,
        }),
        label=_('Email Address'),
        help_text=_('Enter your registered email address')
    )
    
    def clean_email(self):
        """
        Validate email exists and is active.
        """
        email = self.cleaned_data.get('email')
        if email:
            email = email.lower().strip()
            
            try:
                user = User.objects.get(email=email, is_active=True)
                self.user = user
            except User.DoesNotExist:
                # Don't reveal whether email exists
                pass
        
        return email
    
    def save(self):
        """
        Create password reset token and send email.
        """
        if hasattr(self, 'user'):
            # Create reset token
            reset_token = PasswordResetToken.objects.create(
                user=self.user,
                expires_at=timezone.now() + timedelta(hours=1)  # 1 hour expiry
            )
            
            # TODO: Send password reset email
            
            return reset_token
        return None


class PasswordResetConfirmForm(forms.Form):
    """
    Form for confirming password reset with new password.
    """
    
    new_password1 = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'input100',
            'placeholder': 'New Password',
            'required': True,
        }),
        label=_('New Password'),
        help_text=_('Enter your new password')
    )
    
    new_password2 = forms.CharField(
        widget=forms.PasswordInput(attrs={
            'class': 'input100',
            'placeholder': 'Confirm New Password',
            'required': True,
        }),
        label=_('Confirm New Password'),
        help_text=_('Re-enter your new password')
    )
    
    def __init__(self, user=None, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)
    
    def clean_new_password1(self):
        """
        Validate new password strength.
        """
        password = self.cleaned_data.get('new_password1')
        if password and self.user:
            try:
                validate_password(password, self.user)
            except ValidationError as e:
                raise ValidationError(e.messages)
        return password
    
    def clean(self):
        """
        Validate password confirmation.
        """
        cleaned_data = super().clean()
        password1 = cleaned_data.get('new_password1')
        password2 = cleaned_data.get('new_password2')
        
        if password1 and password2 and password1 != password2:
            raise ValidationError(
                _('The two password fields did not match.'),
                code='password_mismatch'
            )
        
        return cleaned_data
    
    def save(self):
        """
        Set new password for user.
        """
        if self.user:
            self.user.set_password(self.cleaned_data['new_password1'])
            self.user.password_changed_at = timezone.now()
            self.user.save()
            return self.user
        return None


class ProfileForm(forms.ModelForm):
    """
    Form for editing user profile information.
    """
    
    class Meta:
        model = Profile
        fields = [
            'phone_number', 'bio', 'job_title', 'company', 'website',
            'address_line1', 'address_line2', 'city', 'state', 'postal_code',
            'country', 'timezone', 'language', 'theme', 'notifications_enabled',
            'email_notifications', 'sms_notifications'
        ]
        widgets = {
            'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
            'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
            'job_title': forms.TextInput(attrs={'class': 'form-control'}),
            'company': forms.TextInput(attrs={'class': 'form-control'}),
            'website': forms.URLInput(attrs={'class': 'form-control'}),
            'address_line1': forms.TextInput(attrs={'class': 'form-control'}),
            'address_line2': forms.TextInput(attrs={'class': 'form-control'}),
            'city': forms.TextInput(attrs={'class': 'form-control'}),
            'state': forms.TextInput(attrs={'class': 'form-control'}),
            'postal_code': forms.TextInput(attrs={'class': 'form-control'}),
            'country': forms.TextInput(attrs={'class': 'form-control'}),
            'timezone': forms.Select(attrs={'class': 'form-control'}),
            'language': forms.Select(attrs={'class': 'form-control'}),
            'theme': forms.Select(attrs={'class': 'form-control'}),
            'notifications_enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'email_notifications': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
            'sms_notifications': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        }
    
    first_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        label=_('First Name')
    )
    
    last_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(attrs={'class': 'form-control'}),
        label=_('Last Name')
    )
    
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super().__init__(*args, **kwargs)
        
        if self.user:
            self.fields['first_name'].initial = self.user.first_name
            self.fields['last_name'].initial = self.user.last_name
    
    def save(self, commit=True):
        """
        Save profile and update user information.
        """
        profile = super().save(commit=False)
        
        if self.user:
            # Update user basic info
            self.user.first_name = self.cleaned_data.get('first_name', '')
            self.user.last_name = self.cleaned_data.get('last_name', '')
            
            if commit:
                self.user.save()
                profile.save()
        
        return profile
