import logging
import warnings

from django.core.exceptions import ValidationError
from django.forms import fields
from django.utils.translation import ugettext_lazy as _
from django import forms

from accounts.forms import EmailRequiredPersonForm, EmailNotRequiredPersonForm
from accounts.constants import STATE_CHOICES
from accounts.profile import get_profile
from accounts import utils as account_utils

from catalog.models import Subscription
from store_order.models import OrderItemGiftDetail

from . import constants
from . import renderers
from . import utils
from .templatetags import storefront_tags


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


class HelpForm(forms.Form):
    """ Simple Help Form """

    reason_for_message = fields.ChoiceField(
        choices=constants.REASONS_FOR_MESSAGE, required=True
    )
    name = forms.CharField(
        widget=forms.Textarea(attrs={"rows": 1, "columns": 45}), required=True
    )
    email = forms.CharField(
        widget=forms.Textarea(attrs={"rows": 1, "columns": 45}), required=True
    )
    message = forms.CharField(
        widget=forms.Textarea(attrs={"rows": 5, "columns": 55}), required=True
    )


class SubscriptionForm(forms.Form):
    """ Subscription form is used to display subscription options. These
    include:

        title: Title of the newspaper.  Available types are calculated using
            the SHIPPING TYPE

        duration: Duration of the subscription choice

        shipping_method: These are typically regular or first class.  Foreign
            addresses qualify only for Foreign First Class

        shipping_type: Shipping type is a function of the users address. If it
            can't be calculated, we expect this value to be None.  The affect
            on the form is that all possible values are returned for all
            fields.
    """

    subscription = None

    def __init__(self, *args, **kwargs):
        self.shipping_type = kwargs.pop("shipping_type", None)
        self.use_account_number = kwargs.pop("use_account_number", None)
        self.renewal = kwargs.pop("renewal", False)
        super(SubscriptionForm, self).__init__(*args, **kwargs)

        self.fields["title"] = forms.ChoiceField(
            label=_("Title"),
            widget=forms.RadioSelect(
                renderer=renderers.HorizontalRadioRenderer,
                attrs={"onclick": "calculate_price();"},
            ),
            choices=utils.unique_titles(self.shipping_type),
            required=True,
            initial=0,
        )

        self.fields["duration"] = forms.ChoiceField(
            label=_("Duration (months)"),
            widget=forms.RadioSelect(
                renderer=renderers.HorizontalRadioRenderer,
                attrs={"onclick": "calculate_price();"},
            ),
            choices=utils.unique_durations(self.shipping_type),
            required=True,
            initial=0,
        )

        self.fields["shipping_method"] = forms.ChoiceField(
            label=_("Shipping Method"),
            widget=forms.RadioSelect(
                renderer=renderers.HorizontalRadioRenderer,
                attrs={"onclick": "calculate_price();"},
            ),
            choices=utils.unique_shipping_methods(),
            required=True,
            initial=0,
        )

        if self.use_account_number:
            self.fields["account_number"] = forms.CharField(
                label=_("Account Number)"),
                required=False,
                widget=forms.TextInput(
                    attrs={"type": "text", "size": 50, "maxlength": 7}
                ),
            )

    def save(self):
        """ Returns the unique subscription calculated by clean """
        return self.subscription

    def clean(self):
        """ Cleans the form data. Uses the form data to determine if the
        subscription product exists.

        title, shipping method, duration and shipping type are used to
        determine if a valid subscription exists.  If one does not, a
        validation error will be returned

        """
        LOG.debug("Subscription Form Data: {0}".format(self.cleaned_data))
        title = self.cleaned_data.get("title", None)
        shipping_method = self.cleaned_data.get("shipping_method", None)
        duration = self.cleaned_data.get("duration", None)
        shipping_type = self.shipping_type

        # recast values from radio button positions to searchable values
        title = utils.get_value_by_index(utils.unique_titles(shipping_type), title)
        duration = utils.get_value_by_index(
            utils.unique_durations(shipping_type), duration
        )
        shipping_method = utils.get_value_by_index(
            utils.unique_shipping_methods(), shipping_method
        )

        try:
            LOG.debug(
                "Looking for subscription with: title:{0}, duration:{1},"
                " shipping_type:{2}, shipping_method:{3}".format(
                    title, duration, shipping_type, shipping_method
                )
            )
            self.subscription = Subscription.objects.get(
                title=title,
                duration=duration,
                shipping_type=shipping_type,
                shipping_method=shipping_method,
                renewal=self.renewal,
            )
        except Subscription.DoesNotExist:
            message = (
                u"{0} is not available with for 9-month or 2-year "
                u"durations. Please choose a different duration or "
                u"shipping method.".format(
                    storefront_tags.humanize_shipping_method(shipping_method)
                )
            )
            LOG.debug(message)
            raise forms.ValidationError(_(message))

        return self.cleaned_data


class GiftInformationForm(forms.ModelForm):

    message = forms.CharField(
        widget=forms.Textarea(attrs={"cols": 55, "rows": 3}), required=False,
    )

    class Meta:
        model = OrderItemGiftDetail
        exclude = (
            "first_name",
            "last_name",
            "company",
            "address1",
            "address2",
            "city",
            "region",
            "phone",
            "country",
            "postal_code",
            "plus_four",
            "email",
        )


class ChangeOfAddressForm(forms.Form):

    account_number = forms.CharField(
        required=False, widget=forms.TextInput(attrs={"type": "text", "size": 50})
    )

    date_effective = forms.ChoiceField(
        label=_("Date Effective"),
        widget=forms.RadioSelect(renderer=renderers.HorizontalRadioRenderer),
        choices=constants.DATE_EFFECTIVE_CHOICES,
        required=True,
        initial=constants.NEXT_ISSUE,
    )
    from_date = forms.CharField(required=False)
    to_date = forms.CharField(required=False)

    def __init__(self, *args, **kwargs):
        self.type = kwargs.pop("type", None)
        super(ChangeOfAddressForm, self).__init__(*args, **kwargs)

        self.fields["title"] = forms.ChoiceField(
            label=_("Title"),
            widget=forms.RadioSelect(renderer=renderers.HorizontalRadioRenderer),
            choices=utils.unique_titles(self.type),
            required=True,
            initial=0,
        )

    def clean(self):

        data = self.cleaned_data
        date_effective = data.get("date_effective", None)
        from_date = data.get("from_date", None)
        to_date = data.get("to_date", None)

        if date_effective == constants.RANGE and not from_date and not to_date:
            raise ValidationError(
                _("You must add from and to dates if you " "choose a date range.")
            )

        return self.cleaned_data


class AddressForm(EmailNotRequiredPersonForm):
    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))

        return self.cleaned_data


class GiftToForm(EmailNotRequiredPersonForm):
    def save(self):
        """ Saving the recipient should not create a user account """
        warnings.warn("deprecated", DeprecationWarning)

    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))

        return self.cleaned_data
