from django import forms
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _

from . import models
from . import profile as profile_utils
from . import constants
from . import utils

REQUIRED = (
    u"There was missing information on your order. Please correct " u"the errors below."
)


class BasePersonForm(forms.Form):
    """ There's a common theme of form data for person information. """

    first_name = forms.CharField(
        label=_(u"First name"),
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={"type": "text", "size": 25}),
    )

    last_name = forms.CharField(
        label=_(u"Last name"),
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={"type": "text", "size": 25}),
    )

    company = forms.CharField(
        label=_(u"Company"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    address1 = forms.CharField(
        label=_(u"Address 1"),
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    address2 = forms.CharField(
        label=_(u"Address 2"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    city = forms.CharField(
        label=_(u"City"),
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    region = forms.CharField(
        label=_(u"Region"),
        max_length=30,
        required=True,
        widget=forms.Select(
            choices=constants.STATE_CHOICES,
            attrs={"width": "100px", "onchange": "calculate_price();"},
        ),
    )

    country = forms.CharField(
        label=_(u"Country"),
        max_length=50,
        required=True,
        widget=forms.Select(
            choices=constants.COUNTRIES,
            attrs={"onchange": "check_state(); calculate_price();"},
        ),
    )

    country_other = forms.CharField(
        label=_(u"Other"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 25}),
    )

    postal_code = forms.CharField(
        label=_(u"Postal Code"),
        max_length=15,
        required=True,
        widget=forms.TextInput(
            attrs={"type": "text", "size": 15, "onchange": "calculate_price();"}
        ),
    )

    plus_four = forms.CharField(
        label=_(u"Plus Four"),
        max_length=15,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 15}),
    )

    phone = forms.CharField(
        label=_(u"Phone"),
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )


class EmailRequiredPersonForm(BasePersonForm):
    """ In some cases, we need the email address to be required """

    email = forms.EmailField(
        label=_(u"Email"),
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )


class EmailNotRequiredPersonForm(BasePersonForm):
    """ In some cases, we need the email address to not be required """

    email = forms.EmailField(
        label=_(u"Email"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )


class NonRequiredBasePersonForm(forms.Form):

    first_name = forms.CharField(
        label=_(u"First name"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 25}),
    )

    last_name = forms.CharField(
        label=_(u"Last name"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 25}),
    )

    company = forms.CharField(
        label=_(u"Company"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    address1 = forms.CharField(
        label=_(u"Address 1"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    address2 = forms.CharField(
        label=_(u"Address 2"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    city = forms.CharField(
        label=_(u"City"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )

    region = forms.ChoiceField(
        label=_(u"Region"),
        required=False,
        choices=constants.STATE_CHOICES,
        widget=forms.Select(
            choices=constants.STATE_CHOICES, attrs={"onchange": "calculate_price();"}
        ),
    )

    country = forms.ChoiceField(
        label=_(u"Country"),
        required=False,
        choices=(("", "----------"),) + constants.COUNTRIES,
        widget=forms.Select(
            choices=constants.STATE_CHOICES,
            attrs={"onchange": "check_state(); calculate_price();"},
        ),
    )

    country_other = forms.CharField(
        label=_(u"Other"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 25}),
    )

    postal_code = forms.CharField(
        label=_(u"Postal Code"),
        max_length=15,
        required=False,
        widget=forms.TextInput(
            attrs={"type": "text", "size": 15, "onchange": "calculate_price();"}
        ),
    )

    plus_four = forms.CharField(
        label=_(u"Plus Four"),
        max_length=4,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 15}),
    )

    phone = forms.CharField(
        label=_(u"Phone"),
        max_length=30,
        required=False,
        widget=forms.TextInput(attrs={"type": "text", "size": 50}),
    )


class ProfileCreateForm(EmailRequiredPersonForm):
    """ Form used for creating a new user """

    password1 = forms.CharField(
        label=_("Password"), widget=forms.PasswordInput, required=True
    )

    password2 = forms.CharField(
        label=_("Password confirmation"), widget=forms.PasswordInput, required=True
    )

    def save(self, request=None):
        """ Creates a new user and account. Returns the newly created user. """
        password = self.cleaned_data["password1"]
        username, email, password = (
            self.cleaned_data["email"],
            self.cleaned_data["email"],
            password,
        )
        user = User.objects.create_user(username, email, password)
        user.first_name = self.cleaned_data["first_name"]
        user.last_name = self.cleaned_data["last_name"]
        user.save()

        profile = profile_utils.get_profile(user)
        profile.company = self.cleaned_data["company"]
        profile.address1 = self.cleaned_data["address1"]
        profile.address2 = self.cleaned_data["address2"]
        profile.city = self.cleaned_data["city"]
        profile.region = self.cleaned_data["region"]
        profile.phone = self.cleaned_data["phone"]
        profile.country = self.cleaned_data["country"]
        profile.postal_code = self.cleaned_data["postal_code"]
        profile.plus_four = self.cleaned_data["plus_four"]
        profile.save()

        user = authenticate(username=username, password=password)
        if request:
            login(request, user)
            site = Site.objects.get_current()
            utils.send_new_account_email(email, password, user, profile, site)

        return user

    def clean(self):
        # We want a single error message.  We don't display the validation
        # errors for each part of the form
        for field in self.fields:
            if self.fields[field].required and not self.cleaned_data.get(field, None):
                raise forms.ValidationError(_(REQUIRED))
        self.clean_email()

        return self.cleaned_data

    def clean_email(self):
        """ Validate that the e-mail address is unique. """
        if User.objects.filter(
            email__iexact=self.cleaned_data["email"]
        ) or User.objects.filter(username__iexact=self.cleaned_data["email"]):
            raise forms.ValidationError(
                _("This email is already in use. " "Please supply a different email.")
            )
        return self.cleaned_data["email"]

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1", "")
        password2 = self.cleaned_data["password2"]
        if password1 != password2:
            raise forms.ValidationError(
                "Your passwords did not match. Please re-enter your passwords."
            )
        return password2


class ProfileUpdateForm(EmailRequiredPersonForm):
    """
    A form to demonstrate how to add extra fields to the signup form, in this
    case adding the first and last name.
    """

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super(ProfileUpdateForm, self).__init__(*args, **kwargs)

    def clean_email(self):
        """ Validate that the email is not already registered with another user
        """
        if User.objects.filter(email__iexact=self.cleaned_data["email"]).exclude(
            email__iexact=self.user.email
        ):
            raise forms.ValidationError(
                _(u"This email is already in use. Please supply a different " u"email.")
            )
        return self.cleaned_data["email"]

    def save(self, request=None):
        """
        Override the save method to save the first and last name to the user
        field.

        """
        user = self.user
        user.first_name = self.cleaned_data["first_name"]
        user.last_name = self.cleaned_data["last_name"]
        user.email = self.cleaned_data["email"]
        user.save()

        profile = profile_utils.get_profile(user)
        profile.company = self.cleaned_data["company"]
        profile.address1 = self.cleaned_data["address1"]
        profile.address2 = self.cleaned_data["address2"]
        profile.city = self.cleaned_data["city"]
        profile.region = self.cleaned_data["region"]
        profile.phone = self.cleaned_data["phone"]
        profile.country = self.cleaned_data["country"]
        profile.country_other = self.cleaned_data["country_other"]
        profile.postal_code = self.cleaned_data["postal_code"]
        profile.plus_four = self.cleaned_data["plus_four"]
        profile.save()

        # Userena expects to get the new user from this form, so return the new
        # user.
        return user


class ProfileSecondaryAddressForm(NonRequiredBasePersonForm):

    address_from = forms.DateField(required=False)
    address_to = forms.DateField(required=False)

    class Meta:
        model = models.SecondaryProfileAddress
        exclude = "profile"

    def __init__(self, *args, **kw):
        super(ProfileSecondaryAddressForm, self).__init__(*args, **kw)

    def save(self, *args, **kwargs):
        user = kwargs.pop("user", None)
        profile_address = profile_utils.get_profile_secondary_address(user)
        profile_address.profile = profile_utils.get_profile(user)
        for k, v in self.cleaned_data.iteritems():
            setattr(profile_address, k, v)
        profile_address.save()
        return profile_address
