import logging
from datetime import timedelta

import pytz
from django.contrib import messages
from django.db.models import Q
from django.shortcuts import redirect
from django.utils.formats import date_format
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView, ListView

from pretix.base.i18n import language
from pretix.base.models import LogEntry, Order
from pretix.base.services.mail import SendMailException, mail
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.multidomain.urlreverse import build_absolute_uri

from . import forms

logger = logging.getLogger('pretix.plugins.sendmail')


class SenderView(EventPermissionRequiredMixin, FormView):
    template_name = 'pretixplugins/sendmail/send_form.html'
    permission = 'can_change_orders'
    form_class = forms.MailForm

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['event'] = self.request.event
        return kwargs

    def form_invalid(self, form):
        messages.error(self.request, _('We could not send the email. See below for details.'))
        return super().form_invalid(form)

    def form_valid(self, form):
        qs = Order.objects.filter(event=self.request.event)
        statusq = Q(status__in=form.cleaned_data['sendto'])
        if 'overdue' in form.cleaned_data['sendto']:
            statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now())
        orders = qs.filter(statusq)

        tz = pytz.timezone(self.request.event.settings.timezone)

        failures = []
        self.output = {}
        if not orders:
            messages.error(self.request, _('There are no orders matching this selection.'))
            return self.get(self.request, *self.args, **self.kwargs)
        for o in orders:
            if self.request.POST.get("action") == "preview":
                for l in self.request.event.settings.locales:
                    with language(l):
                        self.output[l] = []
                        self.output[l].append(_('Subject: {subject}').format(subject=form.cleaned_data['subject'].localize(l)))
                        message = form.cleaned_data['message'].localize(l)
                        preview_text = message.format(
                            order='ORDER1234',
                            event=self.request.event.name,
                            order_date=date_format(now(), 'SHORT_DATE_FORMAT'),
                            due_date=date_format(now() + timedelta(days=7), 'SHORT_DATE_FORMAT'),
                            order_url=build_absolute_uri(self.request.event, 'presale:event.order', kwargs={
                                'order': 'ORDER1234',
                                'secret': 'longrandomsecretabcdef123456'
                            }))
                        self.output[l].append(preview_text)
                return self.get(self.request, *self.args, **self.kwargs)
            else:
                try:
                    with language(o.locale):
                        mail(o.email, form.cleaned_data['subject'], form.cleaned_data['message'],
                             {
                                 'event': o.event,
                                 'order': o.code,
                                 'order_date': date_format(o.datetime.astimezone(tz), 'SHORT_DATETIME_FORMAT'),
                                 'due_date': date_format(o.expires, 'SHORT_DATE_FORMAT'),
                                 'order_url': build_absolute_uri(o.event, 'presale:event.order', kwargs={
                                     'order': o.code,
                                     'secret': o.secret
                                 })},
                             self.request.event, locale=o.locale, order=o)
                        o.log_action(
                            'pretix.plugins.sendmail.order.email.sent',
                            user=self.request.user,
                            data={
                                'subject': form.cleaned_data['subject'],
                                'message': form.cleaned_data['message'],
                                'recipient': o.email
                            }
                        )
                except SendMailException:
                    failures.append(o.email)
        self.request.event.log_action('pretix.plugins.sendmail.sent',
                                      user=self.request.user,
                                      data=dict(form.cleaned_data))
        if failures:
            messages.error(self.request, _('Failed to send mails to the following users: {}'.format(' '.join(failures))))
        else:
            messages.success(self.request, _('Your message has been queued and will be sent to the selected users.'))

        return redirect(
            'plugins:sendmail:send',
            event=self.request.event.slug,
            organizer=self.request.event.organizer.slug
        )

    def get_context_data(self, *args, **kwargs):
        ctx = super().get_context_data(*args, **kwargs)
        ctx['output'] = getattr(self, 'output', None)
        return ctx


class EmailHistoryView(EventPermissionRequiredMixin, ListView):
    template_name = 'pretixplugins/sendmail/history.html'
    permission = 'can_change_orders'
    model = LogEntry
    context_object_name = 'logs'
    paginate_by = 5

    def get_queryset(self):
        qs = LogEntry.objects.filter(
            event=self.request.event,
            action_type='pretix.plugins.sendmail.sent'
        )
        return qs

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data()

        status = dict(Order.STATUS_CHOICE)
        status['overdue'] = _('pending with payment overdue')
        for log in ctx['logs']:
            log.pdata = log.parsed_data
            log.pdata['locales'] = {}
            for locale, msg in log.pdata['message'].items():
                log.pdata['locales'][locale] = {
                    'message': msg,
                    'subject': log.pdata['subject'][locale]
                }
            log.pdata['sendto'] = [
                status[s] for s in log.pdata['sendto']
            ]

        return ctx
