from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.formats import localize
from django.utils.timezone import now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _

from pretix.base.forms import I18nModelForm, PlaceholderValidator
from pretix.base.models import (
    InvoiceAddress, Item, ItemAddOn, Order, OrderPosition,
)
from pretix.base.models.event import SubEvent
from pretix.base.services.pricing import get_price


class ExtendForm(I18nModelForm):
    quota_ignore = forms.BooleanField(
        label=_('Overbook quota'),
        help_text=_('If you check this box, this operation will be performed even if it leads to an overbooked quota '
                    'and you having sold more tickets than you planned!'),
        required=False
    )

    class Meta:
        model = Order
        fields = ['expires']
        widgets = {
            'expires': forms.DateInput(attrs={
                'class': 'datepickerfield',
                'data-is-payment-date': 'true'
            })
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance.status == Order.STATUS_PENDING or self.instance._is_still_available(now(), count_waitinglist=False) is True:
            del self.fields['quota_ignore']

    def clean(self):
        data = super().clean()
        data['expires'] = data['expires'].replace(hour=23, minute=59, second=59)
        if data['expires'] < now():
            raise ValidationError(_('The new expiry date needs to be in the future.'))
        return data


class ExporterForm(forms.Form):

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

        for k, v in data.items():
            if isinstance(v, models.Model):
                data[k] = v.pk
            elif isinstance(v, models.QuerySet):
                data[k] = [m.pk for m in v]

        return data


class CommentForm(I18nModelForm):
    class Meta:
        model = Order
        fields = ['comment']
        widgets = {
            'comment': forms.Textarea(attrs={
                'rows': 3,
                'class': 'helper-width-100',
            }),
        }


class SubEventChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        p = get_price(self.instance.item, self.instance.variation,
                      voucher=self.instance.voucher,
                      subevent=obj)
        return '{} – {} ({} {})'.format(obj.name, obj.get_date_range_display(),
                                        p, self.instance.order.event.currency)


class OtherOperationsForm(forms.Form):
    recalculate_taxes = forms.BooleanField(
        label=_('Re-calculate taxes'),
        required=False,
        help_text=_(
            'This operation re-checks if taxes should be paid to the items due to e.g. configured reverse charge rules '
            'and changes the prices and tax values accordingly. This is useful e.g. after an invoice address change. '
            'Use with care and only if you need to. Note that rounding differences might occur in this procedure.'
        )
    )
    notify = forms.BooleanField(
        label=_('Notify user'),
        required=False,
        initial=True,
        help_text=_(
            'Send an email to the customer notifying that their order has been changed.'
        )
    )

    def __init__(self, *args, **kwargs):
        kwargs.pop('order')
        super().__init__(*args, **kwargs)


class OrderPositionAddForm(forms.Form):
    do = forms.BooleanField(
        label=_('Add a new product to the order'),
        required=False
    )
    itemvar = forms.ChoiceField(
        label=_('Product')
    )
    addon_to = forms.ModelChoiceField(
        OrderPosition.objects.none(),
        required=False,
        label=_('Add-on to'),
    )
    price = forms.DecimalField(
        required=False,
        max_digits=10, decimal_places=2,
        label=_('Gross price'),
        help_text=_("Including taxes, if any. Keep empty for the product's default price")
    )
    subevent = forms.ModelChoiceField(
        SubEvent.objects.none(),
        label=pgettext_lazy('subevent', 'Date'),
        required=True,
        empty_label=None
    )

    def __init__(self, *args, **kwargs):
        order = kwargs.pop('order')
        super().__init__(*args, **kwargs)

        try:
            ia = order.invoice_address
        except InvoiceAddress.DoesNotExist:
            ia = None

        choices = []
        for i in order.event.items.prefetch_related('variations').all():
            pname = str(i.name)
            if not i.is_available():
                pname += ' ({})'.format(_('inactive'))
            variations = list(i.variations.all())
            if variations:
                for v in variations:
                    p = get_price(i, v, invoice_address=ia)
                    choices.append(('%d-%d' % (i.pk, v.pk),
                                    '%s – %s (%s %s)' % (pname, v.value, p, order.event.currency)))
            else:
                p = get_price(i, invoice_address=ia)
                choices.append((str(i.pk), '%s (%s %s)' % (pname, p, order.event.currency)))
        self.fields['itemvar'].choices = choices
        if ItemAddOn.objects.filter(base_item__event=order.event).exists():
            self.fields['addon_to'].queryset = order.positions.filter(addon_to__isnull=True).select_related(
                'item', 'variation'
            )
        else:
            del self.fields['addon_to']

        if order.event.has_subevents:
            self.fields['subevent'].queryset = order.event.subevents.all()
        else:
            del self.fields['subevent']


class OrderPositionChangeForm(forms.Form):
    itemvar = forms.ChoiceField()
    subevent = SubEventChoiceField(
        SubEvent.objects.none(),
        label=pgettext_lazy('subevent', 'New date'),
        required=True,
        empty_label=None
    )
    price = forms.DecimalField(
        required=False,
        max_digits=10, decimal_places=2,
        label=_('New price (gross)')
    )
    operation = forms.ChoiceField(
        required=False,
        widget=forms.RadioSelect,
        choices=(
            ('product', 'Change product'),
            ('price', 'Change price'),
            ('subevent', 'Change event date'),
            ('cancel', 'Remove product'),
            ('split', 'Split into new order'),
        )
    )

    def __init__(self, *args, **kwargs):
        instance = kwargs.pop('instance')
        initial = kwargs.get('initial', {})

        try:
            ia = instance.order.invoice_address
        except InvoiceAddress.DoesNotExist:
            ia = None

        if instance:
            try:
                if instance.variation:
                    initial['itemvar'] = '%d-%d' % (instance.item.pk, instance.variation.pk)
                elif instance.item:
                    initial['itemvar'] = str(instance.item.pk)
            except Item.DoesNotExist:
                pass

            if instance.item.tax_rule and not instance.item.tax_rule.price_includes_tax:
                initial['price'] = instance.price - instance.tax_value
            else:
                initial['price'] = instance.price
        initial['subevent'] = instance.subevent

        kwargs['initial'] = initial
        super().__init__(*args, **kwargs)
        if instance.order.event.has_subevents:
            self.fields['subevent'].instance = instance
            self.fields['subevent'].queryset = instance.order.event.subevents.all()
        else:
            del self.fields['subevent']

        choices = []
        for i in instance.order.event.items.prefetch_related('variations').all():
            pname = str(i.name)
            if not i.is_available():
                pname += ' ({})'.format(_('inactive'))
            variations = list(i.variations.all())

            if variations:
                for v in variations:
                    p = get_price(i, v, voucher=instance.voucher, subevent=instance.subevent,
                                  invoice_address=ia)
                    choices.append(('%d-%d' % (i.pk, v.pk),
                                    '%s – %s (%s %s)' % (pname, v.value, localize(p),
                                                         instance.order.event.currency)))
            else:
                p = get_price(i, None, voucher=instance.voucher, subevent=instance.subevent,
                              invoice_address=ia)
                choices.append((str(i.pk), '%s (%s %s)' % (pname, localize(p),
                                                           instance.order.event.currency)))
        self.fields['itemvar'].choices = choices

    def clean(self):
        if self.cleaned_data.get('operation') == 'price' and not self.cleaned_data.get('price', '') != '':
            raise ValidationError(_('You need to enter a price if you want to change the product price.'))


class OrderContactForm(forms.ModelForm):
    regenerate_secrets = forms.BooleanField(required=False, label=_('Invalidate secrets'),
                                            help_text=_('Regenerates the order and ticket secrets. You will '
                                                        'need to re-send the link to the order page to the user and '
                                                        'the user will need to download his tickets again. The old '
                                                        'versions will be invalid.'))

    class Meta:
        model = Order
        fields = ['email']


class OrderLocaleForm(forms.ModelForm):
    locale = forms.ChoiceField()

    class Meta:
        model = Order
        fields = ['locale']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        locale_names = dict(settings.LANGUAGES)
        self.fields['locale'].choices = [(a, locale_names[a]) for a in self.instance.event.settings.locales]


class OrderMailForm(forms.Form):
    subject = forms.CharField(
        label=_("Subject"),
        required=True
    )

    def __init__(self, *args, **kwargs):
        order = kwargs.pop('order')
        super().__init__(*args, **kwargs)
        self.fields['sendto'] = forms.EmailField(
            label=_("Recipient"),
            required=True,
            initial=order.email
        )
        self.fields['sendto'].widget.attrs['readonly'] = 'readonly'
        self.fields['message'] = forms.CharField(
            label=_("Message"),
            required=True,
            widget=forms.Textarea,
            initial=order.event.settings.mail_text_order_custom_mail.localize(order.locale),
            help_text=_("Available placeholders: {expire_date}, {event}, {code}, {date}, {url}, "
                        "{invoice_name}, {invoice_company}"),
            validators=[PlaceholderValidator(['{expire_date}', '{event}', '{code}', '{date}', '{url}',
                                              '{invoice_name}', '{invoice_company}'])]
        )
