from django import forms
from django.contrib.auth import password_validation, update_session_auth_hash
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm, UsernameField, SetPasswordForm, \
    PasswordResetForm
from django.contrib.auth.tokens import default_token_generator
from django.core.validators import EmailValidator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.utils.translation import ugettext as _
from mailing.mail_service import EmailSender
from users.auth_backends import ApprenticeModelBackend
from users.models import Apprentice
from utils.general import get_base_url_from_request


class ApprenticeAuthenticationForm(AuthenticationForm):
    """Formularz logowania użytkownika."""

    error_messages = {
        'invalid_login': _('Błędne dane logowania'),
        'inactive': _('This account is inactive.'),
    }

    def __init__(self, request=None, *args, **kwargs):
        super(AuthenticationForm, self).__init__(*args, **kwargs)
        self.fields['username'].validators.append(EmailValidator())
        self.fields['username'].label = _('Adres e-mail')

    def clean(self):
        email = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        if email and password:
            self.user_cache = ApprenticeModelBackend.direct_authenticate(username=email, password=password)
            if self.user_cache is None:
                raise forms.ValidationError(self.error_messages['invalid_login'], code='invalid_login',
                                            params={'username': _(u'Email')})
            elif not self.user_cache.is_active:
                raise forms.ValidationError(self.error_messages['inactive'], code='inactive')

        return self.cleaned_data


class ApprenticeCreateForm(UserCreationForm):
    """Formularz dodawania nowego użytkownika."""

    class Meta:
        model = Apprentice
        fields = ('username', 'email')
        field_classes = {'username': UsernameField}

    def __init__(self, *args, **kwargs):
        super(UserCreationForm, self).__init__(*args, **kwargs)
        self.fields['email'].required = True
        self.fields['password2'].required = False

    def clean_email(self):
        email = self.cleaned_data.get('email')
        username = self.cleaned_data.get('username')
        if email and Apprentice.objects.filter(email=email).exclude(username=username).exists():
            raise forms.ValidationError(_('Podany adres Email już istnieje.'))
        return email

    def clean_password2(self):
        data = self.cleaned_data.get('password2')
        return data

    def save(self, commit=True):
        user = super(ApprenticeCreateForm, self).save(commit=True)
        return user


class ApprenticeUpdateForm(forms.ModelForm):
    """Formularz edycji użytkownika."""

    error_messages = {
        'password_mismatch': _('Podane hasła do siebie nie pasują.'),
    }
    new_password1 = forms.CharField(widget=forms.PasswordInput, strip=False,
                                    help_text=password_validation.password_validators_help_text_html(), required=False,
                                    label=_('Hasło'))
    new_password2 = forms.CharField(strip=False, widget=forms.PasswordInput, required=False, label=_('Hasło (powtórz)'))

    class Meta:
        model = Apprentice
        fields = ('username', 'email')

    def __init__(self, *args, **kwargs):
        super(ApprenticeUpdateForm, self).__init__(*args, **kwargs)
        self.fields['email'].required = True
        self.fields['username'].required = True
        if not self.errors.get('email'):
            self.fields['email'].widget.attrs['readonly'] = True
        if not self.errors.get('username'):
            self.fields['username'].widget.attrs['readonly'] = True
        if not self.errors.get('new_password2') or self.errors.get('new_password1'):
            self.fields['new_password1'].widget.attrs['readonly'] = True

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if email and email != self.instance.email:
            if Apprentice.objects.filter(email=email).exists():
                raise forms.ValidationError(_('Podany adres Email już istnieje.'))
        return email

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if username and username != self.instance.username:
            if Apprentice.objects.filter(username=username).exists():
                raise forms.ValidationError(_('Podana nazwa użytkownika już istnieje.'))
        return username

    def clean_new_password2(self):
        password1 = self.cleaned_data.get('new_password1')
        password2 = self.cleaned_data.get('new_password2')
        if password1 and password2:
            if password1 != password2:
                raise forms.ValidationError(
                    self.error_messages['password_mismatch'],
                    code='password_mismatch',
                )
            password_validation.validate_password(password2, self.instance)
        return password2

    def save(self, request=None, commit=True):
        apprentice = self.instance
        username = self.cleaned_data.get('username')
        if username:
            apprentice.username = username
        email = self.cleaned_data.get('email')
        if email:
            apprentice.email = email
        password = self.cleaned_data.get('new_password2')
        if password:
            apprentice.set_password(password)
            update_session_auth_hash(request, self.instance)
        if username or email or password:
            apprentice.save()


class ApprenticePasswordResetForm(PasswordResetForm):
    email = forms.EmailField(label=_("Email"), max_length=254)

    def save(self, request=None, **kwargs):
        email = self.cleaned_data["email"]
        apprentices = Apprentice.objects.filter(email=email)
        for apprentice in apprentices:
            token_generator = default_token_generator
            token = token_generator.make_token(apprentice)
            uid = urlsafe_base64_encode(force_bytes(apprentice.pk))
            BASE_SITE_URL = get_base_url_from_request(request)
            EmailSender.send_recovery_password_email(apprentice.email,
                                                     {'BASE_SITE_URL': BASE_SITE_URL, 'uid': uid, 'token': token})


class ApprenticePasswordChangeForm(SetPasswordForm):
    pass
