import magic
import os

from datetime import datetime
from time import mktime

from django import forms
from django.conf import settings

from .models import Document, Correspondent


class UploadForm(forms.Form):

    TYPE_LOOKUP = {
        "application/pdf": Document.TYPE_PDF,
        "image/png": Document.TYPE_PNG,
        "image/jpeg": Document.TYPE_JPG,
        "image/gif": Document.TYPE_GIF,
        "image/tiff": Document.TYPE_TIF,
    }

    correspondent = forms.CharField(
        max_length=Correspondent._meta.get_field("name").max_length,
        required=False
    )
    title = forms.CharField(
        max_length=Document._meta.get_field("title").max_length,
        required=False
    )
    document = forms.FileField()

    def __init__(self, *args, **kwargs):
        forms.Form.__init__(self, *args, **kwargs)
        self._file_type = None

    def clean_correspondent(self):
        """
        I suppose it might look cleaner to use .get_or_create() here, but that
        would also allow someone to fill up the db with bogus correspondents
        before all validation was met.
        """

        corresp = self.cleaned_data.get("correspondent")

        if not corresp:
            return None

        if not Correspondent.SAFE_REGEX.match(corresp) or " - " in corresp:
            raise forms.ValidationError(
                "That correspondent name is suspicious.")

        return corresp

    def clean_title(self):

        title = self.cleaned_data.get("title")

        if not title:
            return None

        if not Correspondent.SAFE_REGEX.match(title) or " - " in title:
            raise forms.ValidationError("That title is suspicious.")

        return title

    def clean_document(self):

        document = self.cleaned_data.get("document").read()

        with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m:
            file_type = m.id_buffer(document)

        if file_type not in self.TYPE_LOOKUP:
            raise forms.ValidationError("The file type is invalid.")

        self._file_type = self.TYPE_LOOKUP[file_type]

        return document

    def save(self):
        """
        Since the consumer already does a lot of work, it's easier just to save
        to-be-consumed files to the consumption directory rather than have the
        form do that as well.  Think of it as a poor-man's queue server.
        """

        correspondent = self.cleaned_data.get("correspondent")
        title = self.cleaned_data.get("title")
        document = self.cleaned_data.get("document")

        t = int(mktime(datetime.now().timetuple()))
        file_name = os.path.join(
            settings.CONSUMPTION_DIR,
            "{} - {}.{}".format(correspondent, title, self._file_type)
        )

        with open(file_name, "wb") as f:
            f.write(document)
            os.utime(file_name, times=(t, t))
