from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _

from ..bans import get_email_ban, get_ip_ban, get_username_ban
from ..validators import validate_email, validate_new_registration, validate_username

User = get_user_model()


class BaseRegisterForm(forms.Form):
    username = forms.CharField()
    email = forms.CharField(validators=[validate_email])

    terms_of_service = forms.IntegerField(required=False)
    privacy_policy = forms.IntegerField(required=False)

    def __init__(self, *args, **kwargs):
        self.agreements = kwargs.pop("agreements")
        self.request = kwargs.pop("request")
        super().__init__(*args, **kwargs)

    def clean_username(self):
        data = self.cleaned_data["username"]

        validate_username(self.request.settings, data)
        ban = get_username_ban(data, registration_only=True)
        if ban:
            if ban.user_message:
                raise ValidationError(ban.user_message)
            else:
                raise ValidationError(_("This username is not allowed."))
        return data

    def clean_email(self):
        data = self.cleaned_data["email"]

        ban = get_email_ban(data, registration_only=True)
        if ban:
            if ban.user_message:
                raise ValidationError(ban.user_message)
            else:
                raise ValidationError(_("This e-mail address is not allowed."))
        return data

    def clean_agreements(self, data):
        for field_name, agreement in self.agreements.items():
            if data.get(field_name) != agreement["id"]:
                error = ValueError(_("This agreement is required."))
                self.add_error(field_name, error)

    def raise_if_ip_banned(self):
        ban = get_ip_ban(self.request.user_ip, registration_only=True)
        if ban:
            if ban.user_message:
                raise ValidationError(ban.user_message)
            else:
                raise ValidationError(
                    _("New registrations from this IP address are not allowed.")
                )


class SocialAuthRegisterForm(BaseRegisterForm):
    def clean(self):
        cleaned_data = super().clean()

        self.clean_agreements(cleaned_data)
        self.raise_if_ip_banned()

        validate_new_registration(self.request, cleaned_data, self.add_error)

        return cleaned_data


class RegisterForm(BaseRegisterForm):
    password = forms.CharField(strip=False)

    # placeholder field for setting captcha errors on form
    captcha = forms.CharField(required=False)

    def full_clean_password(self, cleaned_data):
        if cleaned_data.get("password"):
            validate_password(
                cleaned_data["password"],
                user=User(
                    username=cleaned_data.get("username"),
                    email=cleaned_data.get("email"),
                ),
            )

    def clean(self):
        cleaned_data = super().clean()

        self.clean_agreements(cleaned_data)
        self.raise_if_ip_banned()

        try:
            self.full_clean_password(cleaned_data)
        except forms.ValidationError as e:
            self.add_error("password", e)

        validate_new_registration(self.request, cleaned_data, self.add_error)

        return cleaned_data
