# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import absolute_import
from django import forms
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _

from wiki.plugins.attachments import models
from wiki.core.permissions import can_moderate

import zipfile
from django.core.files.uploadedfile import File
import tempfile
from wiki.plugins.attachments.models import IllegalFileExtension


class AttachmentForm(forms.ModelForm):

    description = forms.CharField(
        label=_('Description'),
        help_text=_('A short summary of what the file contains'),
        required=False
    )

    def __init__(self, *args, **kwargs):
        self.article = kwargs.pop('article', None)
        self.request = kwargs.pop('request', None)
        self.attachment = kwargs.pop('attachment', None)
        super(AttachmentForm, self).__init__(*args, **kwargs)

    def clean_file(self):
        uploaded_file = self.cleaned_data.get('file', None)
        if uploaded_file:
            try:
                models.extension_allowed(uploaded_file.name)
            except IllegalFileExtension as e:
                raise forms.ValidationError(e)
        return uploaded_file

    def save(self, *args, **kwargs):
        commit = kwargs.get('commit', True)
        attachment_revision = super(AttachmentForm, self).save(commit=False)

        # Added because of AttachmentArchiveForm removing file from fields
        # should be more elegant
        attachment_revision.file = self.cleaned_data['file']
        if not self.attachment:
            attachment = models.Attachment()
            attachment.article = self.article
            attachment.original_filename = attachment_revision.get_filename()
            if commit:
                attachment.save()
            attachment.articles.add(self.article)
        else:
            attachment = self.attachment
        attachment_revision.attachment = attachment
        attachment_revision.set_from_request(self.request)
        if commit:
            attachment_revision.save()
        return attachment_revision

    class Meta:
        model = models.AttachmentRevision
        fields = ('file', 'description',)


class AttachmentReplaceForm(AttachmentForm):

    replace = forms.BooleanField(
        label=_('Remove previous'),
        help_text=_('Remove previous attachment revisions and their files (to '
                    'save space)?'),
        required=False,
    )


class AttachmentArchiveForm(AttachmentForm):

    file = forms.FileField(  # @ReservedAssignment
        label=_('File or zip archive'),
        required=True
    )

    unzip_archive = forms.BooleanField(
        label=_('Unzip file'),
        help_text=_(
            'Create individual attachments for files in a .zip file - directories do not work.'),
        required=False)

    def __init__(self, *args, **kwargs):
        super(AttachmentArchiveForm, self).__init__(*args, **kwargs)
        ordered_fields = ['unzip_archive', 'file']
        self.fields.keyOrder = ordered_fields + [k
                                                 for k in list(
                                                     self.fields.keys())
                                                 if k not in ordered_fields]

    def clean_file(self):
        uploaded_file = self.cleaned_data.get('file', None)
        if uploaded_file and self.cleaned_data.get('unzip_archive', False):
            try:
                self.zipfile = zipfile.ZipFile(uploaded_file.file, mode="r")
                for zipinfo in self.zipfile.filelist:
                    try:
                        models.extension_allowed(zipinfo.filename)
                    except IllegalFileExtension as e:
                        raise forms.ValidationError(e)
            except zipfile.BadZipfile:
                raise forms.ValidationError(ugettext("Not a zip file"))
        else:
            return super(AttachmentArchiveForm, self).clean_file()
        return uploaded_file

    def clean(self):
        if not can_moderate(self.article, self.request.user):
            raise forms.ValidationError(
                ugettext("User not allowed to moderate this article"))
        return self.cleaned_data

    def save(self, *args, **kwargs):

        # This is not having the intended effect
        if not 'file' in self._meta.fields:
            self._meta.fields.append('file')

        if self.cleaned_data['unzip_archive']:
            new_attachments = []
            try:
                for zipinfo in self.zipfile.filelist:
                    f = tempfile.NamedTemporaryFile(mode='r+w')
                    f.write(self.zipfile.read(zipinfo.filename))
                    f = File(f, name=zipinfo.filename)
                    try:
                        attachment = models.Attachment()
                        attachment.article = self.article
                        attachment.original_filename = zipinfo.filename
                        attachment.save()
                        attachment.articles.add(self.article)
                        attachment_revision = models.AttachmentRevision()
                        attachment_revision.file = f
                        attachment_revision.description = self.cleaned_data[
                            'description']
                        attachment_revision.attachment = attachment
                        attachment_revision.set_from_request(self.request)
                        attachment_revision.save()
                        f.close()
                    except models.IllegalFileExtension:
                        raise
                    new_attachments.append(attachment_revision)
            except zipfile.BadZipfile:
                raise
            return new_attachments
        else:
            return super(AttachmentArchiveForm, self).save(*args, **kwargs)

    class Meta(AttachmentForm.Meta):
        fields = ['description', ]


class DeleteForm(forms.Form):

    """This form is both used for dereferencing and deleting attachments"""
    confirm = forms.BooleanField(label=_('Yes I am sure...'),
                                 required=False)

    def clean_confirm(self):
        if not self.cleaned_data['confirm']:
            raise forms.ValidationError(ugettext('You are not sure enough!'))
        return True


class SearchForm(forms.Form):

    query = forms.CharField(
        label="",
        widget=forms.TextInput(
            attrs={
                'class': 'search-query'}),
    )
