"""
Forms for the accounts app.
"""
import re
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth.password_validation import validate_password
from apps.accounts.models import CustomUser
from utils.choices import ROLE_CHOICES


class StudentSignupForm(UserCreationForm):
    """Form for student registration."""
    full_name = forms.CharField(
        max_length=150,
        required=True,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Full Name'})
    )
    email = forms.EmailField(
        required=True,
        widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email Address'})
    )
    phone_number = forms.CharField(
        max_length=20,
        required=False,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Phone Number (optional)'})
    )
    cnic = forms.CharField(
        max_length=20,
        required=True,
        label='CNIC',
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': 'XXXXX-XXXXXXX-X',
            'maxlength': '15',
            'inputmode': 'numeric',
            'autocomplete': 'off',
            'id': 'id_cnic',
        }),
        help_text='Your 13-digit National Identity Card number (format: XXXXX-XXXXXXX-X)'
    )

    class Meta:
        model = CustomUser
        fields = ('username', 'full_name', 'email', 'phone_number', 'cnic', 'password1', 'password2')
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Username'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['password1'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Password'})
        self.fields['password2'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Confirm Password'})

    def clean_email(self):
        email = self.cleaned_data.get('email', '').strip().lower()
        if CustomUser.objects.filter(email__iexact=email).exists():
            raise forms.ValidationError('An account with this email address already exists.')
        return email

    def clean_cnic(self):
        cnic = self.cleaned_data.get('cnic', '').replace('-', '').replace(' ', '')
        if not re.match(r'^\d{13}$', cnic):
            raise forms.ValidationError('Enter a valid 13-digit CNIC number (dashes are optional).')
        if CustomUser.objects.filter(cnic=cnic).exists():
            raise forms.ValidationError('An account with this CNIC already exists.')
        return cnic

    def save(self, commit=True):
        user = super().save(commit=False)
        user.role = 'student'
        user.full_name = self.cleaned_data['full_name']
        user.phone_number = self.cleaned_data.get('phone_number', '')
        user.cnic = self.cleaned_data.get('cnic', '')
        if commit:
            user.save()
        return user


class EducationBackgroundForm(forms.ModelForm):
    """Required education background when enrolling in a course or applying for a certification."""

    class Meta:
        model = CustomUser
        fields = ('qualification', 'last_degree', 'work_experience', 'age')
        widgets = {
            'qualification': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'e.g. Bachelor of Science, Intermediate, Diploma',
            }),
            'last_degree': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'e.g. BS Computer Science, FA, Matric',
            }),
            'work_experience': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 3,
                'placeholder': 'Brief work experience (or write “Fresher” / “Student”)',
            }),
            'age': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': 10,
                'max': 100,
                'placeholder': 'Age',
            }),
        }
        labels = {
            'qualification': 'Highest qualification',
            'last_degree': 'Last degree / program',
            'work_experience': 'Work experience',
            'age': 'Age',
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['qualification'].required = True
        self.fields['last_degree'].required = True
        self.fields['work_experience'].required = True
        self.fields['age'].required = True

    def clean_qualification(self):
        val = (self.cleaned_data.get('qualification') or '').strip()
        if len(val) < 2:
            raise forms.ValidationError('Please enter your qualification.')
        return val

    def clean_last_degree(self):
        val = (self.cleaned_data.get('last_degree') or '').strip()
        if len(val) < 2:
            raise forms.ValidationError('Please enter your last degree or program.')
        return val

    def clean_work_experience(self):
        val = (self.cleaned_data.get('work_experience') or '').strip()
        if len(val) < 2:
            raise forms.ValidationError('Please describe your work experience (or write Fresher).')
        return val


class TeacherSignupForm(UserCreationForm):
    """Form for teacher registration."""
    full_name = forms.CharField(
        max_length=150,
        required=True,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Full Name'})
    )
    email = forms.EmailField(
        required=True,
        widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email Address'})
    )
    phone_number = forms.CharField(
        max_length=20,
        required=False,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Phone Number (optional)'})
    )
    bio = forms.CharField(
        required=False,
        widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Short bio (optional)'})
    )

    class Meta:
        model = CustomUser
        fields = ('username', 'full_name', 'email', 'phone_number', 'bio', 'password1', 'password2')
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Username'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['password1'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Password'})
        self.fields['password2'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Confirm Password'})

    def save(self, commit=True):
        user = super().save(commit=False)
        user.role = 'teacher'
        user.full_name = self.cleaned_data['full_name']
        user.phone_number = self.cleaned_data.get('phone_number', '')
        user.bio = self.cleaned_data.get('bio', '')
        if commit:
            user.save()
        return user


class CustomLoginForm(AuthenticationForm):
    """Login with username OR email + password."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].label = 'Username or email'
        self.fields['username'].widget.attrs.update({
            'class': 'form-control',
            'placeholder': 'Username or email',
            'autocomplete': 'username',
            'autofocus': True,
        })
        self.fields['password'].widget.attrs.update({
            'class': 'form-control',
            'placeholder': 'Password',
            'autocomplete': 'current-password',
        })

    def clean_username(self):
        return (self.cleaned_data.get('username') or '').strip()


class ProfileUpdateForm(forms.ModelForm):
    """Form for updating user profile."""
    class Meta:
        model = CustomUser
        fields = (
            'full_name', 'email', 'phone_number', 'cnic',
            'age', 'qualification', 'last_degree', 'work_experience',
            'reference_name', 'reference_mobile',
            'bio', 'profile_picture',
        )
        widgets = {
            'full_name':        forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Full Name'}),
            'email':            forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email Address'}),
            'phone_number':     forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Phone Number'}),
            'cnic':             forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'XXXXX-XXXXXXX-X', 'maxlength': '15', 'inputmode': 'numeric', 'autocomplete': 'off', 'id': 'id_cnic_profile'}),
            'age':              forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Age', 'min': 10, 'max': 100}),
            'qualification':    forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'e.g. Bachelor of Science'}),
            'last_degree':      forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'e.g. BS Computer Science'}),
            'work_experience':  forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Briefly describe your work experience'}),
            'reference_name':   forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Reference person\'s full name'}),
            'reference_mobile': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Reference person\'s mobile number'}),
            'bio':              forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Short bio about yourself'}),
            'profile_picture':  forms.FileInput(attrs={'class': 'form-control'}),
        }
        labels = {
            'cnic':             'CNIC',
            'age':              'Age',
            'qualification':    'Qualification',
            'last_degree':      'Last Degree',
            'work_experience':  'Work Experience',
            'reference_name':   'Reference Name',
            'reference_mobile': 'Reference Mobile',
        }

    def clean_cnic(self):
        import re
        cnic = self.cleaned_data.get('cnic', '').replace('-', '').replace(' ', '')
        if not cnic:
            return None
        if not re.match(r'^\d{13}$', cnic):
            raise forms.ValidationError('Enter a valid 13-digit CNIC number (dashes are optional).')
        qs = CustomUser.objects.filter(cnic=cnic)
        if self.instance and self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if qs.exists():
            raise forms.ValidationError('An account with this CNIC already exists.')
        return cnic


class AdminUserCreateForm(UserCreationForm):
    """Form for admin to create a user with any role."""
    full_name = forms.CharField(
        max_length=150, required=True,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Full Name'})
    )
    email = forms.EmailField(
        required=True,
        widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email Address'})
    )
    role = forms.ChoiceField(
        choices=ROLE_CHOICES,
        widget=forms.Select(attrs={'class': 'form-select'})
    )
    phone_number = forms.CharField(
        max_length=20, required=False,
        widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Phone Number (optional)'})
    )
    cnic = forms.CharField(
        max_length=20,
        required=False,
        label='CNIC',
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': '13-digit CNIC e.g. 12345-6789012-3',
        }),
        help_text='13-digit National Identity Card number (optional for admin-created users)'
    )

    class Meta:
        model = CustomUser
        fields = ('username', 'full_name', 'email', 'role', 'phone_number', 'cnic', 'password1', 'password2')
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Username'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['password1'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Password'})
        self.fields['password2'].widget.attrs.update({'class': 'form-control', 'placeholder': 'Confirm Password'})

    def clean_cnic(self):
        cnic = self.cleaned_data.get('cnic', '').replace('-', '').replace(' ', '')
        if not cnic:
            return cnic
        if not re.match(r'^\d{13}$', cnic):
            raise forms.ValidationError('Enter a valid 13-digit CNIC number (dashes are optional).')
        if CustomUser.objects.filter(cnic=cnic).exists():
            raise forms.ValidationError('An account with this CNIC already exists.')
        return cnic

    def save(self, commit=True):
        user = super().save(commit=False)
        user.full_name = self.cleaned_data['full_name']
        user.role = self.cleaned_data['role']
        user.phone_number = self.cleaned_data.get('phone_number', '')
        user.cnic = self.cleaned_data.get('cnic', '') or None
        if commit:
            user.save()
        return user


class AdminUserUpdateForm(forms.ModelForm):
    """Admin: edit user details and role."""
    class Meta:
        model = CustomUser
        fields = ('full_name', 'email', 'role', 'phone_number', 'is_active')
        widgets = {
            'full_name': forms.TextInput(attrs={'class': 'form-control'}),
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'role': forms.Select(attrs={'class': 'form-select'}),
            'phone_number': forms.TextInput(attrs={'class': 'form-control'}),
            'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
        }

    def clean_email(self):
        email = self.cleaned_data.get('email', '').strip().lower()
        qs = CustomUser.objects.filter(email__iexact=email)
        if self.instance and self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if email and qs.exists():
            raise forms.ValidationError('Another account already uses this email.')
        return email


class ForgotPasswordForm(forms.Form):
    """Step 1 of password reset: verify identity via email + CNIC."""
    email = forms.EmailField(
        widget=forms.EmailInput(attrs={
            'class': 'form-control',
            'placeholder': 'Registered email address',
            'autofocus': True,
        })
    )
    cnic = forms.CharField(
        max_length=20,
        label='CNIC',
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': '13-digit CNIC (e.g. 12345-6789012-3)',
        })
    )

    def clean_cnic(self):
        cnic = self.cleaned_data.get('cnic', '').replace('-', '').replace(' ', '')
        if not re.match(r'^\d{13}$', cnic):
            raise forms.ValidationError('Enter a valid 13-digit CNIC number.')
        return cnic


class SetNewPasswordForm(forms.Form):
    """Step 2 of password reset: choose a new password."""
    new_password1 = forms.CharField(
        label='New Password',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': 'New password',
            'autofocus': True,
        })
    )
    new_password2 = forms.CharField(
        label='Confirm New Password',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': 'Confirm new password',
        })
    )

    def clean_new_password1(self):
        password = self.cleaned_data.get('new_password1')
        if password:
            try:
                validate_password(password)
            except forms.ValidationError as e:
                raise forms.ValidationError(e.messages)
        return password

    def clean(self):
        cleaned_data = super().clean()
        p1 = cleaned_data.get('new_password1')
        p2 = cleaned_data.get('new_password2')
        if p1 and p2 and p1 != p2:
            raise forms.ValidationError('The two password fields did not match.')
        return cleaned_data


class ChangePasswordForm(forms.Form):
    """Logged-in user: change password (requires current password)."""
    current_password = forms.CharField(
        label='Current password',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': 'Current password',
            'autocomplete': 'current-password',
            'autofocus': True,
        }),
    )
    new_password1 = forms.CharField(
        label='New password',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': 'New password',
            'autocomplete': 'new-password',
        }),
    )
    new_password2 = forms.CharField(
        label='Confirm new password',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': 'Confirm new password',
            'autocomplete': 'new-password',
        }),
    )

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

    def clean_current_password(self):
        current = self.cleaned_data.get('current_password')
        if not self.user.check_password(current):
            raise forms.ValidationError('Your current password is incorrect.')
        return current

    def clean_new_password1(self):
        password = self.cleaned_data.get('new_password1')
        if password:
            try:
                validate_password(password, self.user)
            except forms.ValidationError as e:
                raise forms.ValidationError(list(e.messages))
        return password

    def clean(self):
        cleaned = super().clean()
        p1 = cleaned.get('new_password1')
        p2 = cleaned.get('new_password2')
        if p1 and p2 and p1 != p2:
            raise forms.ValidationError('The two new password fields did not match.')
        return cleaned

    def save(self):
        password = self.cleaned_data['new_password1']
        self.user.set_password(password)
        self.user.save()
        return self.user

