from django import forms
from django.contrib.auth import password_validation
from django.contrib.auth.forms import PasswordChangeForm as DjangoPasswordChangeForm
from django.core.exceptions import ValidationError

from .models import User
from .profile_setup import company_initials, unique_slug


class LoginForm(forms.Form):
    email = forms.EmailField(
        widget=forms.EmailInput(
            attrs={
                'class': 'auth-input',
                'placeholder': 'your@email.com',
                'autocomplete': 'email',
            }
        )
    )
    password = forms.CharField(
        widget=forms.PasswordInput(
            attrs={
                'class': 'auth-input auth-input-password',
                'placeholder': 'Enter your password',
                'autocomplete': 'current-password',
            }
        )
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = None

    def clean(self):
        cleaned_data = super().clean()
        email = cleaned_data.get('email')
        password = cleaned_data.get('password')

        if email and password:
            user = User.objects.filter(email__iexact=email.strip()).order_by('id').first()
            if user is None:
                raise ValidationError('Invalid email or password.')

            if not user.check_password(password):
                raise ValidationError('Invalid email or password.')

            if not user.is_active:
                raise ValidationError('This account has been disabled.')

            self.user = user
            cleaned_data['user'] = user

        return cleaned_data


class SeekerRegistrationForm(forms.ModelForm):
    password1 = forms.CharField(
        label='Password',
        widget=forms.PasswordInput(
            attrs={'class': 'reg-input', 'placeholder': 'Min. 8 characters', 'autocomplete': 'new-password'}
        ),
    )
    password2 = forms.CharField(
        label='Confirm password',
        widget=forms.PasswordInput(
            attrs={'class': 'reg-input', 'placeholder': 'Repeat password', 'autocomplete': 'new-password'}
        ),
    )
    accept_terms = forms.BooleanField(
        required=True,
        error_messages={'required': 'Please accept the Terms of Service and Privacy Policy to continue.'},
    )

    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'email', 'phone']
        widgets = {
            'first_name': forms.TextInput(attrs={'class': 'reg-input', 'placeholder': 'e.g. Chanda', 'autocomplete': 'given-name'}),
            'last_name': forms.TextInput(attrs={'class': 'reg-input', 'placeholder': 'e.g. Mwila', 'autocomplete': 'family-name'}),
            'email': forms.EmailInput(attrs={'class': 'reg-input', 'placeholder': 'you@email.com', 'autocomplete': 'email'}),
            'phone': forms.TextInput(attrs={'class': 'reg-input', 'placeholder': '+260 97X XXX XXX', 'autocomplete': 'tel', 'inputmode': 'tel'}),
        }

    def clean_email(self):
        email = self.cleaned_data['email'].lower()
        if User.objects.filter(email__iexact=email).exists():
            raise ValidationError('An account with this email already exists.')
        return email

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2 and password1 != password2:
            raise ValidationError('Passwords do not match.')
        password_validation.validate_password(password2)
        return password2

    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = user.email.lower()
        user.username = self._build_username(user.email)
        user.role = User.Role.SEEKER
        user.set_password(self.cleaned_data['password1'])
        if commit:
            user.save()
            self._create_seeker_profile(user)
        return user

    @staticmethod
    def _create_seeker_profile(user):
        from seekers.models import SeekerProfile

        full_name = f'{user.first_name} {user.last_name}'.strip() or user.username
        SeekerProfile.objects.get_or_create(
            user=user,
            defaults={
                'slug': unique_slug(SeekerProfile, full_name),
                'full_name': full_name,
                'headline': 'Job Seeker',
                'category': 'General',
                'location': 'Lusaka',
                'is_public': False,
            },
        )

    @staticmethod
    def _build_username(email: str) -> str:
        base = email.split('@')[0].replace('.', '_')[:30]
        username = base
        counter = 1
        while User.objects.filter(username=username).exists():
            suffix = str(counter)
            username = f'{base[: 30 - len(suffix)]}{suffix}'
            counter += 1
        return username


class CompanyRegistrationForm(forms.ModelForm):
    company_name = forms.CharField(
        max_length=150,
        widget=forms.TextInput(
            attrs={'class': 'reg-input', 'placeholder': 'e.g. Airtel Zambia'}
        ),
    )
    contact_person = forms.CharField(
        max_length=150,
        widget=forms.TextInput(
            attrs={'class': 'reg-input', 'placeholder': 'HR Manager\'s name'}
        ),
    )
    password1 = forms.CharField(
        label='Password',
        widget=forms.PasswordInput(
            attrs={'class': 'reg-input', 'placeholder': 'Min. 8 characters', 'autocomplete': 'new-password'}
        ),
    )
    password2 = forms.CharField(
        label='Confirm password',
        widget=forms.PasswordInput(
            attrs={'class': 'reg-input', 'placeholder': 'Repeat password', 'autocomplete': 'new-password'}
        ),
    )
    accept_terms = forms.BooleanField(
        required=True,
        error_messages={'required': 'Please accept the Terms of Service and Privacy Policy to continue.'},
    )

    class Meta:
        model = User
        fields = ['email', 'phone']
        widgets = {
            'email': forms.EmailInput(attrs={'class': 'reg-input', 'placeholder': 'hr@company.com', 'autocomplete': 'email'}),
            'phone': forms.TextInput(attrs={'class': 'reg-input', 'placeholder': '+260 2XX XXX XXX', 'autocomplete': 'tel', 'inputmode': 'tel'}),
        }

    def clean_email(self):
        email = self.cleaned_data['email'].lower()
        if User.objects.filter(email__iexact=email).exists():
            raise ValidationError('An account with this email already exists.')
        return email

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2 and password1 != password2:
            raise ValidationError('Passwords do not match.')
        password_validation.validate_password(password2)
        return password2

    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = user.email.lower()
        user.username = SeekerRegistrationForm._build_username(user.email)
        user.role = User.Role.COMPANY
        user.first_name = self.cleaned_data['contact_person']
        user.last_name = self.cleaned_data['company_name'][:150]
        user.set_password(self.cleaned_data['password1'])
        company_name = self.cleaned_data['company_name']
        if commit:
            user.save()
            self._create_company_profile(user, company_name)
        return user

    @staticmethod
    def _create_company_profile(user, company_name):
        from companies.models import Company

        Company.objects.get_or_create(
            owner=user,
            defaults={
                'name': company_name,
                'slug': unique_slug(Company, company_name),
                'initials': company_initials(company_name),
                'industry': 'General',
                'location': 'Lusaka',
                'description': f'{company_name} is hiring talented professionals on PEZAJOB.',
                'is_active': True,
            },
        )


class AccountSettingsForm(forms.ModelForm):
    clear_avatar = forms.BooleanField(
        required=False,
        label='Remove current profile photo',
    )
    clear_cover_image = forms.BooleanField(
        required=False,
        label='Remove cover photo',
    )

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'phone', 'avatar', 'cover_image']
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Username'}),
            'first_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'First name'}),
            'last_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Last name'}),
            'email': forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'you@email.com'}),
            'phone': forms.TextInput(attrs={'class': 'form-control', 'placeholder': '+260 97X XXX XXX'}),
            'avatar': forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'}),
            'cover_image': forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['cover_image'].label = 'Cover photo'
        self.fields['cover_image'].help_text = (
            'Banner image for your admin profile. Recommended size: 1200×400 px or wider.'
        )
        if not self.instance.is_platform_admin:
            self.fields.pop('cover_image', None)
            self.fields.pop('clear_cover_image', None)

    def clean_username(self):
        username = self.cleaned_data['username'].strip()
        if not username:
            raise ValidationError('Username is required.')
        qs = User.objects.filter(username__iexact=username)
        if self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if qs.exists():
            raise ValidationError('This username is already taken.')
        return username

    def clean_email(self):
        email = self.cleaned_data['email'].strip().lower()
        qs = User.objects.filter(email__iexact=email)
        if self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if qs.exists():
            raise ValidationError('An account with this email already exists.')
        return email

    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = self.cleaned_data['email'].lower()
        if self.cleaned_data.get('clear_avatar') and user.avatar:
            user.avatar.delete(save=False)
            user.avatar = None
        if 'clear_cover_image' in self.fields and self.cleaned_data.get('clear_cover_image') and user.cover_image:
            user.cover_image.delete(save=False)
            user.cover_image = None
        if commit:
            user.save()
            self._sync_seeker_name(user)
        return user

    @staticmethod
    def _sync_seeker_name(user):
        if not user.is_seeker:
            return
        from seekers.models import SeekerProfile

        profile = SeekerProfile.objects.filter(user=user).first()
        if not profile:
            return
        full_name = user.get_full_name().strip()
        if full_name and profile.full_name != full_name:
            profile.full_name = full_name
            profile.save(update_fields=['full_name', 'updated_at'])


class AdminUserForm(forms.ModelForm):
    clear_avatar = forms.BooleanField(
        required=False,
        label='Remove profile photo',
    )

    class Meta:
        model = User
        fields = [
            'username',
            'first_name',
            'last_name',
            'email',
            'phone',
            'role',
            'is_active',
            'is_staff',
            'is_superuser',
            'avatar',
        ]
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control'}),
            'first_name': forms.TextInput(attrs={'class': 'form-control'}),
            'last_name': forms.TextInput(attrs={'class': 'form-control'}),
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'phone': forms.TextInput(attrs={'class': 'form-control'}),
            'role': forms.Select(attrs={'class': 'form-control'}),
            'avatar': forms.FileInput(attrs={'class': 'form-control', 'accept': 'image/*'}),
        }

    def clean_username(self):
        username = self.cleaned_data['username'].strip()
        if not username:
            raise ValidationError('Username is required.')
        qs = User.objects.filter(username__iexact=username)
        if self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if qs.exists():
            raise ValidationError('This username is already taken.')
        return username

    def clean_email(self):
        email = self.cleaned_data['email'].strip().lower()
        qs = User.objects.filter(email__iexact=email)
        if self.instance.pk:
            qs = qs.exclude(pk=self.instance.pk)
        if qs.exists():
            raise ValidationError('An account with this email already exists.')
        return email

    def save(self, commit=True):
        user = super().save(commit=False)
        user.email = self.cleaned_data['email'].lower()
        if self.cleaned_data.get('clear_avatar') and user.avatar:
            user.avatar.delete(save=False)
            user.avatar = None
        if commit:
            user.save()
            AccountSettingsForm._sync_seeker_name(user)
        return user


class AdminSetPasswordForm(forms.Form):
    new_password1 = forms.CharField(
        label='New password',
        required=True,
        widget=forms.PasswordInput(attrs={'class': 'form-control', 'autocomplete': 'new-password'}),
    )
    new_password2 = forms.CharField(
        label='Confirm new password',
        required=True,
        widget=forms.PasswordInput(attrs={'class': 'form-control', 'autocomplete': 'new-password'}),
    )

    def __init__(self, *args, user=None, **kwargs):
        self.user = user
        super().__init__(*args, **kwargs)

    def clean(self):
        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('Passwords do not match.')
        if password1:
            password_validation.validate_password(password1, self.user)
        return cleaned_data

    def save(self):
        if not self.cleaned_data.get('new_password1'):
            return
        self.user.set_password(self.cleaned_data['new_password1'])
        self.user.save(update_fields=['password'])


class AccountPasswordChangeForm(DjangoPasswordChangeForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs.setdefault('class', 'form-control')
            if isinstance(field.widget, forms.PasswordInput):
                field.widget.attrs.setdefault('autocomplete', 'new-password')
        self.fields['old_password'].widget.attrs['autocomplete'] = 'current-password'
        # Django autofocuses this field, which makes the settings page scroll down to it on every visit.
        self.fields['old_password'].widget.attrs.pop('autofocus', None)
