from django import forms
from django.contrib.auth import get_user_model, authenticate
from django.contrib.auth.forms import UserCreationForm, PasswordResetForm, AuthenticationForm
from .models import UserProfile
from django.core.validators import RegexValidator
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.template import loader
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
from django.db import transaction

User = get_user_model()


class PhoneAuthenticationForm(AuthenticationForm):
    """
    Custom authentication form that uses phone number instead of username.
    """
    username = forms.CharField(
        label='手机号码',
        max_length=16,
        widget=forms.TextInput(attrs={
            'autofocus': True,
            'placeholder': '请输入手机号码'
        })
    )
    
    def __init__(self, request=None, *args, **kwargs):
        super().__init__(request, *args, **kwargs)
        # Update the field label and help text
        self.fields['username'].label = '手机号码'
        self.fields['password'].label = '密码'
    
    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        if username is not None and password:
            # Use phone as username for authentication
            self.user_cache = authenticate(
                self.request,
                phone=username,
                password=password
            )
            if self.user_cache is None:
                raise self.get_invalid_login_error()
            else:
                self.confirm_login_allowed(self.user_cache)

        return self.cleaned_data


class UserRegistrationForm(UserCreationForm):
    phone = forms.CharField(
        max_length=16,
        label='电话号码',
        help_text='此号码将用于登录'
    )
    
    email = forms.EmailField(
        max_length=50,
        required=True,
        label='电子邮箱',
        help_text='请输入有效的电子邮箱地址'
    )
    
    gender = forms.ChoiceField(
        choices=User.GENDER_CHOICES,
        label='性别',
        initial='N',
        widget=forms.RadioSelect
    )
    
    # Profile fields
    birth_date = forms.DateField(
        widget=forms.DateInput(attrs={'type': 'date'}),
        required=False,
        label='出生日期'
    )
    
    birth_time = forms.TimeField(
        widget=forms.TimeInput(attrs={'type': 'time'}),
        required=False,
        label='出生时间'
    )
    
    twin_type = forms.ChoiceField(
        choices=UserProfile.TWIN_TYPE_CHOICES,
        required=False,
        label='双胞胎类型'
    )
    
    father_dob = forms.DateField(
        widget=forms.DateInput(attrs={'type': 'date'}),
        required=False,
        label='父亲出生日期 (双胞胎大必填)'
    )
    
    mother_dob = forms.DateField(
        widget=forms.DateInput(attrs={'type': 'date'}),
        required=False,
        label='母亲出生日期 (双胞胎小必填)'
    )
    
    class Meta:
        model = User
        fields = ['phone', 'email', 'first_name', 'last_name', 'password1', 'password2', 'gender']
        labels = {
            'first_name': '名字',
            'last_name': '姓氏',
            'gender': '性别',
        }
    
    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        if User.objects.filter(phone=phone).exists():
            raise forms.ValidationError('此电话号码已被使用')
        return phone
    
    def clean_email(self):
        email = self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('此电子邮箱已被使用')
        return email
    
    def clean(self):
        cleaned_data = super().clean()
        twin_type = cleaned_data.get('twin_type')
        father_dob = cleaned_data.get('father_dob')
        mother_dob = cleaned_data.get('mother_dob')
        
        if twin_type == '1' and not father_dob:
            self.add_error('father_dob', '双胞胎大必须填写父亲出生日期')
        
        if twin_type == '2' and not mother_dob:
            self.add_error('mother_dob', '双胞胎小必须填写母亲出生日期')
        
        return cleaned_data
    
    def save(self, commit=True):
        user = super().save(commit=False)
        if commit:
            user.save()
            # Update the existing profile that was created by the signal
            profile = user.profile
            profile.birth_date = self.cleaned_data.get('birth_date')
            profile.birth_time = self.cleaned_data.get('birth_time')
            profile.twin_type = self.cleaned_data.get('twin_type')
            profile.father_dob = self.cleaned_data.get('father_dob')
            profile.mother_dob = self.cleaned_data.get('mother_dob')
            profile.save()
        return user

class UserForm(forms.ModelForm):
    phone = forms.CharField(
        max_length=16,
        label='电话号码',
        help_text='此号码将用于登录'
    )
    
    email = forms.EmailField(
        max_length=50,
        required=True,
        label='电子邮箱',
        help_text='请输入有效的电子邮箱地址'
    )
    
    gender = forms.ChoiceField(
        choices=User.GENDER_CHOICES,
        label='性别',
        widget=forms.RadioSelect
    )
    
    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'phone', 'email', 'gender']
        labels = {
            'first_name': '名字',
            'last_name': '姓氏',
            'phone': '电话号码',
            'email': '电子邮箱',
            'gender': '性别',
        }
    
    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        if User.objects.exclude(pk=self.instance.pk).filter(phone=phone).exists():
            raise forms.ValidationError('此电话号码已被使用')
        return phone
    
    def clean_email(self):
        email = self.cleaned_data.get('email')
        if User.objects.exclude(pk=self.instance.pk).filter(email=email).exists():
            raise forms.ValidationError('此电子邮箱已被使用')
        return email

class ProfileForm(forms.ModelForm):
    birth_date = forms.DateField(
        widget=forms.DateInput(attrs={'type': 'date'}),
        required=False,
        label='出生日期'
    )
    
    birth_time = forms.TimeField(
        widget=forms.TimeInput(attrs={'type': 'time'}),
        required=False,
        label='出生时间'
    )
    
    twin_type = forms.ChoiceField(
        choices=UserProfile.TWIN_TYPE_CHOICES,
        required=False,
        label='双胞胎类型'
    )
    
    father_dob = forms.DateField(
        widget=forms.DateInput(attrs={'type': 'date'}),
        required=False,
        label='父亲出生日期 (双胞胎大必填)'
    )
    
    mother_dob = forms.DateField(
        widget=forms.DateInput(attrs={'type': 'date'}),
        required=False,
        label='母亲出生日期 (双胞胎小必填)'
    )
    
    class Meta:
        model = UserProfile
        fields = ['birth_date', 'birth_time', 'twin_type', 'father_dob', 'mother_dob']
    
    def clean(self):
        cleaned_data = super().clean()
        twin_type = cleaned_data.get('twin_type')
        father_dob = cleaned_data.get('father_dob')
        mother_dob = cleaned_data.get('mother_dob')
        
        if twin_type == '1' and not father_dob:
            self.add_error('father_dob', '双胞胎大必须填写父亲出生日期')
        
        if twin_type == '2' and not mother_dob:
            self.add_error('mother_dob', '双胞胎小必须填写母亲出生日期')
        
        return cleaned_data

class AccountDeletionForm(forms.Form):
    password = forms.CharField(
        widget=forms.PasswordInput(attrs={'class': 'form-control'}),
        label='请输入您的密码',
        help_text='请输入您的密码以确认您的身份。'
    )
    reason = forms.CharField(
        widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
        label='删除原因（可选）',
        required=False,
        help_text='请告诉我们您为什么要删除账户。这将帮助我们改进我们的服务。'
    )
    
    def __init__(self, user=None, *args, **kwargs):
        self.user = user
        super(AccountDeletionForm, self).__init__(*args, **kwargs)
    
    def clean_password(self):
        password = self.cleaned_data.get('password')
        if not self.user.check_password(password):
            raise forms.ValidationError('密码不正确。')
        return password

class PublicAccountDeletionForm(forms.Form):
    phone = forms.CharField(
        label='手机号码',
        max_length=16,
        widget=forms.TextInput(attrs={'class': 'form-control'})
    )
    email = forms.EmailField(
        label='电子邮箱',
        widget=forms.EmailInput(attrs={'class': 'form-control'})
    )
    reason = forms.CharField(
        label='删除原因（选填）',
        required=False,
        widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3})
    )

    def clean(self):
        cleaned_data = super().clean()
        phone = cleaned_data.get('phone')
        email = cleaned_data.get('email')

        # Check if an account exists with this phone and email
        try:
            user = User.objects.get(phone=phone, email=email)
        except User.DoesNotExist:
            # We don't want to reveal if the account exists or not
            pass

        return cleaned_data

class QuickRegistrationForm(forms.Form):
    """Form for quick registration from number power results."""
    phone = forms.CharField(
        label='手机号码',
        max_length=16,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入手机号码'})
    )
    email = forms.EmailField(
        label='电子邮箱',
        max_length=50,
        widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': '请输入电子邮箱'})
    )
    password = forms.CharField(
        label='密码',
        widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'})
    )
    password2 = forms.CharField(
        label='确认密码',
        widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请再次输入密码'})
    )
    
    # Hidden fields for person data
    name = forms.CharField(widget=forms.HiddenInput(), required=False)
    gender = forms.CharField(widget=forms.HiddenInput(), required=False)
    birth_date = forms.CharField(widget=forms.HiddenInput(), required=False)
    birth_time = forms.CharField(widget=forms.HiddenInput(), required=False)
    twin_type = forms.CharField(widget=forms.HiddenInput(), required=False)
    father_dob = forms.CharField(widget=forms.HiddenInput(), required=False)
    mother_dob = forms.CharField(widget=forms.HiddenInput(), required=False)
    
    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        if User.objects.filter(phone=phone).exists():
            raise forms.ValidationError('此电话号码已被使用')
        return phone
    
    def clean_email(self):
        email = self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError('此电子邮箱已被使用')
        return email
    
    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password2 = cleaned_data.get('password2')
        
        if password and password2 and password != password2:
            self.add_error('password2', '两次输入的密码不一致')
        
        return cleaned_data 

class CustomPasswordResetForm(PasswordResetForm):
    """
    Custom password reset form that uses hardcoded domain from settings
    instead of relying on the request hostname.
    """
    
    def save(self, domain_override=None, subject_template_name='registration/password_reset_subject.txt',
             email_template_name='registration/password_reset_email.html',
             use_https=None, token_generator=default_token_generator,
             from_email=None, request=None, html_email_template_name=None,
             extra_email_context=None):
        """
        Generate a one-use only link for resetting password and send it to the user.
        Override the save method to use hardcoded domain from settings.
        """
        # Use hardcoded domain from settings if available
        if hasattr(settings, 'PASSWORD_RESET_DOMAIN') and settings.PASSWORD_RESET_DOMAIN:
            domain_override = settings.PASSWORD_RESET_DOMAIN
        
        # Use hardcoded HTTPS setting if available
        if hasattr(settings, 'PASSWORD_RESET_USE_HTTPS'):
            use_https = settings.PASSWORD_RESET_USE_HTTPS
        elif use_https is None:
            use_https = False
        
        # Call the parent save method with our domain override
        super().save(
            domain_override=domain_override,
            subject_template_name=subject_template_name,
            email_template_name=email_template_name,
            use_https=use_https,
            token_generator=token_generator,
            from_email=from_email,
            request=request,
            html_email_template_name=html_email_template_name,
            extra_email_context=extra_email_context
        )


# Temporary User Forms

class TemporaryUserRegistrationForm(forms.Form):
    """
    Form for temporary users to register a permanent account.
    Pre-fills data from their first BaZi record if available.
    """
    # Required fields
    phone = forms.CharField(
        label='手机号码',
        max_length=30,  # Increased to accommodate temp user phones (temp_1234567890_abcdefgh = 24 chars)
        widget=forms.TextInput(attrs={
            'class': 'form-control', 
            'placeholder': '请输入手机号码'
        })
    )
    email = forms.EmailField(
        label='电子邮箱',
        max_length=50,
        widget=forms.EmailInput(attrs={
            'class': 'form-control', 
            'placeholder': '请输入电子邮箱'
        })
    )
    
    # Optional password
    password = forms.CharField(
        label='密码（可选）',
        required=False,
        widget=forms.PasswordInput(attrs={
            'class': 'form-control', 
            'placeholder': '设置密码（可选，不设置可稍后重设）'
        }),
        help_text='可以暂时不设置密码，稍后通过忘记密码功能设置'
    )
    password2 = forms.CharField(
        label='确认密码',
        required=False,
        widget=forms.PasswordInput(attrs={
            'class': 'form-control', 
            'placeholder': '再次输入密码'
        })
    )
    
    # Optional profile fields (pre-filled from BaZi record)
    first_name = forms.CharField(
        label='名字',
        max_length=150,
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control', 
            'placeholder': '请输入名字'
        })
    )
    last_name = forms.CharField(
        label='姓氏',
        max_length=150,
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control', 
            'placeholder': '请输入姓氏'
        })
    )
    gender = forms.ChoiceField(
        choices=User.GENDER_CHOICES,
        label='性别',
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    birth_date = forms.DateField(
        label='出生日期',
        required=False,
        widget=forms.DateInput(attrs={
            'type': 'date',
            'class': 'form-control'
        })
    )
    birth_time = forms.TimeField(
        label='出生时间',
        required=False,
        widget=forms.TimeInput(attrs={
            'type': 'time',
            'class': 'form-control'
        })
    )
    twin_type = forms.ChoiceField(
        choices=UserProfile.TWIN_TYPE_CHOICES,
        label='双胞胎类型',
        required=False,
        widget=forms.Select(attrs={'class': 'form-control'})
    )
    father_dob = forms.DateField(
        label='父亲出生日期',
        required=False,
        widget=forms.DateInput(attrs={
            'type': 'date',
            'class': 'form-control'
        })
    )
    mother_dob = forms.DateField(
        label='母亲出生日期',
        required=False,
        widget=forms.DateInput(attrs={
            'type': 'date',
            'class': 'form-control'
        })
    )
    
    def __init__(self, temp_user=None, *args, **kwargs):
        self.temp_user = temp_user
        super().__init__(*args, **kwargs)
        
        # Pre-fill form with data from first BaZi record if available
        if temp_user:
            from .utils import get_first_bazi_record, extract_user_data_from_bazi
            first_bazi = get_first_bazi_record(temp_user)
            if first_bazi:
                data = extract_user_data_from_bazi(first_bazi)
                for field, value in data.items():
                    if field in self.fields and value is not None:
                        self.fields[field].initial = value
    
    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        # Exclude the current temp user when checking for duplicates
        existing_users = User.objects.filter(phone=phone)
        if self.temp_user:
            existing_users = existing_users.exclude(id=self.temp_user.id)
        if existing_users.exists():
            raise forms.ValidationError('此电话号码已被使用')
        return phone
    
    def clean_email(self):
        email = self.cleaned_data.get('email')
        # Exclude the current temp user when checking for duplicates
        existing_users = User.objects.filter(email=email)
        if self.temp_user:
            existing_users = existing_users.exclude(id=self.temp_user.id)
        if existing_users.exists():
            raise forms.ValidationError('此电子邮箱已被使用')
        return email
    
    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password2 = cleaned_data.get('password2')
        
        # Only validate password match if password is provided
        if password:
            if password != password2:
                self.add_error('password2', '两次输入的密码不一致')
        
        # Twin type validation
        twin_type = cleaned_data.get('twin_type')
        father_dob = cleaned_data.get('father_dob')
        mother_dob = cleaned_data.get('mother_dob')
        
        if twin_type == '1' and not father_dob:
            self.add_error('father_dob', '双胞胎大必须填写父亲出生日期')
        
        if twin_type == '2' and not mother_dob:
            self.add_error('mother_dob', '双胞胎小必须填写母亲出生日期')
        
        return cleaned_data
    
    @transaction.atomic
    def save(self, temp_user):
        """
        Convert temporary user to permanent user.
        """
        from .utils import transfer_user_data, cleanup_temp_user
        import secrets
        import string
        
        cleaned_data = self.cleaned_data
        
        # Update temporary user to permanent user
        temp_user.phone = cleaned_data['phone']
        temp_user.email = cleaned_data['email']
        temp_user.first_name = cleaned_data.get('first_name', '')
        temp_user.last_name = cleaned_data.get('last_name', '')
        temp_user.gender = cleaned_data.get('gender', 'N')
        temp_user.is_temporary_user = False
        
        # Set password or generate a random one if not provided
        password = cleaned_data.get('password')
        if password:
            temp_user.set_password(password)
        else:
            # Generate a secure random password
            random_password = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(12))
            temp_user.set_password(random_password)
        
        temp_user.save()
        
        # Update or create profile
        from accounts.models import UserProfile
        profile, created = UserProfile.objects.get_or_create(user=temp_user)
        
        # Update profile fields - use is not None to handle 0 values properly
        # Also check for empty strings which should be treated as None for optional fields
        if cleaned_data.get('birth_date') is not None:
            profile.birth_date = cleaned_data.get('birth_date')
        if cleaned_data.get('birth_time') is not None:
            profile.birth_time = cleaned_data.get('birth_time')
        
        # Special handling for twin_type to avoid empty string issues
        twin_type = cleaned_data.get('twin_type')
        if twin_type is not None and twin_type != '':
            try:
                profile.twin_type = int(twin_type) if isinstance(twin_type, str) else twin_type
            except (ValueError, TypeError):
                # Skip invalid values
                pass
        # If twin_type is None or empty string, don't modify the existing value
        
        if cleaned_data.get('father_dob') is not None:
            profile.father_dob = cleaned_data.get('father_dob')
        if cleaned_data.get('mother_dob') is not None:
            profile.mother_dob = cleaned_data.get('mother_dob')
        
        profile.save()
        
        return temp_user


 