# coding=utf-8
import io
from wsgiref.util import FileWrapper

from django.contrib import messages
from django.http import HttpResponse
from django.shortcuts import redirect, get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import DeleteView
from django.views.generic import ListView

from web.decorators import PermissionDecorator
from web.docx_helper import merge_files
from . import WrappedView
from . import wrap_response
from ..forms.mail_template import MailTemplateForm
from ..models import StudySubject, Visit, Appointment, MailTemplate, Voucher
from ..models.constants import MAIL_TEMPLATE_CONTEXT_SUBJECT, MAIL_TEMPLATE_CONTEXT_VISIT, \
    MAIL_TEMPLATE_CONTEXT_APPOINTMENT, MAIL_TEMPLATE_CONTEXT_VOUCHER

MIMETYPE_DOCX = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'

CONTEXT_TYPES_MAPPING = {
    MAIL_TEMPLATE_CONTEXT_SUBJECT: StudySubject,
    MAIL_TEMPLATE_CONTEXT_VISIT: Visit,
    MAIL_TEMPLATE_CONTEXT_VOUCHER: Voucher,
    MAIL_TEMPLATE_CONTEXT_APPOINTMENT: Appointment
}


class MailTemplatesListView(ListView, WrappedView):
    model = MailTemplate
    context_object_name = "mail_templates"
    template_name = 'mail_templates/list.html'

    @PermissionDecorator('change_mailtemplate', 'mailtemplate')
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data()
        MailTemplate.update_tags()
        context['explanations'] = {"generic": MailTemplate.MAILS_TEMPLATE_GENERIC_TAGS,
                                   "subject": MailTemplate.MAILS_TEMPLATE_SUBJECT_TAGS,
                                   "visit": MailTemplate.MAILS_TEMPLATE_VISIT_TAGS,
                                   "voucher": MailTemplate.MAILS_TEMPLATE_VOUCHER_TAGS,
                                   "appointment": MailTemplate.MAILS_TEMPLATE_APPOINTMENT_TAGS,
                                   }
        return context


@PermissionDecorator('change_mailtemplate', 'mailtemplate')
def mail_template_add(request):
    if request.method == 'POST':
        form = MailTemplateForm(request.POST, request.FILES)
        if form.is_valid():
            try:
                form.save()
            except:
                messages.add_message(request, messages.ERROR, 'There was a problem when saving template. '
                                                              'Contact system administrator.')
            return redirect('web.views.mail_templates')
    else:
        form = MailTemplateForm()

    return wrap_response(request, 'mail_templates/add.html', {'form': form})


@PermissionDecorator('change_mailtemplate', 'mailtemplate')
def mail_template_edit(request, pk):
    template = get_object_or_404(MailTemplate, pk=pk)
    if request.method == 'POST':
        form = MailTemplateForm(request.POST, request.FILES, instance=template)
        if form.is_valid():
            try:
                form.save()
                return redirect('web.views.mail_templates')
            except:
                messages.add_message(request, messages.ERROR, 'There was a problem when updating template. '
                                                              'Contact system administrator.')
                return wrap_response(request, 'mail_templates/edit.html', {'form': form, 'mail_template': template})
    else:
        form = MailTemplateForm(instance=template)

    return wrap_response(request, 'mail_templates/edit.html', {'form': form, 'mail_template': template})


class MailTemplatesDeleteView(DeleteView, WrappedView):
    model = MailTemplate
    success_url = reverse_lazy('web.views.mail_templates')
    template_name = 'mail_templates/confirm_delete.html'

    @PermissionDecorator('change_mailtemplate', 'mailtemplate')
    def delete(self, request, *args, **kwargs):
        messages.success(request, "Template deleted")
        try:
            return super().delete(request, *args, **kwargs)
        except:
            messages.add_message(request, messages.ERROR, 'There was a problem when deleting template. '
                                                          'Contact system administrator.')
        return redirect('web.views.mail_templates')


def generate(request, mail_template_id, instance_id):
    mail_template = get_object_or_404(MailTemplate, id=mail_template_id)
    instance = get_object_or_404(CONTEXT_TYPES_MAPPING[mail_template.context], id=instance_id)
    stream = io.BytesIO()
    stream = mail_template.apply(instance, request.user, stream)
    file_size = stream.tell()
    stream.seek(0)
    response = HttpResponse(FileWrapper(stream), content_type=MIMETYPE_DOCX)
    response['Content-Length'] = file_size
    response['Content-Disposition'] = 'attachment; filename={}.docx'.format(mail_template.name)
    return response


def generate_for_vouchers(request):
    ids = request.GET.get('voucher_id', '').split(',')
    vouchers = []
    for voucher_id in ids:
        if voucher_id.isdigit():
            vouchers.append(Voucher.objects.get(pk=int(voucher_id)))
    templates = MailTemplate.get_voucher_mail_templates([])[0]

    if len(templates) == 0:
        messages.add_message(request, messages.WARNING,
                             'There are no voucher mail templates. Please add one in order to print vouchers.')
        return redirect(request.META.get('HTTP_REFERER', 'web.views.subjects'))

    output_stream = io.BytesIO()

    inputs = []
    for template in templates:
        for voucher in vouchers:
            input_stream = io.BytesIO()
            input_stream = template.apply(voucher, request.user, input_stream)
            input_stream.seek(0)
            inputs.append(input_stream)

    if len(inputs) == 0:
        return redirect(request.META.get('HTTP_REFERER', 'web.views.subjects'))

    merge_files(inputs, output_stream)
    file_size = output_stream.tell()
    output_stream.seek(0)
    response = HttpResponse(FileWrapper(output_stream), content_type=MIMETYPE_DOCX)
    response['Content-Length'] = file_size
    response['Content-Disposition'] = 'attachment; filename=vouchers.docx'
    return response