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