from __future__ import print_function

import base64

import six

from django.conf import settings
from django.db import models
from django.utils import timezone

from database_files import utils
from database_files.utils import write_file, is_fresh
from database_files.manager import FileManager

from . import settings as _settings


class File(models.Model):

    objects = FileManager()

    name = models.CharField(max_length=255, unique=True, blank=False, null=False, db_index=True)

    size = models.PositiveIntegerField(db_index=True, blank=False, null=False)

    _content = models.TextField(db_column='content')

    created_datetime = models.DateTimeField(db_index=True, default=timezone.now, verbose_name="Created datetime")

    _content_hash = models.CharField(db_column='content_hash', db_index=True, max_length=128, blank=True, null=True)

    class Meta:
        db_table = 'database_files_file'

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

        # Check for and clear old content hash.
        if self.id:
            old = File.objects.get(id=self.id)
            if old._content != self._content:
                self._content_hash = None

        # Recalculate new content hash.
        self.content_hash

        return super(File, self).save(*args, **kwargs)

    @property
    def content(self):
        c = self._content
        if not isinstance(c, six.binary_type):
            c = c.encode('utf-8')
        return base64.b64decode(c)

    @content.setter
    def content(self, v):
        c = base64.b64encode(v)
        if not isinstance(c, six.string_types):
            c = c.decode('utf-8')
        self._content = c

    @property
    def content_hash(self):
        if not self._content_hash and self._content:
            self._content_hash = utils.get_text_hash(self.content)
        return self._content_hash

    def dump(self, check_hash=False):
        """
        Writes the file content to the filesystem.
        
        If check_hash is true, clears the stored file hash and recalculates.
        """
        if is_fresh(self.name, self._content_hash):
            return
        write_file(self.name, self.content, overwrite=True)
        if check_hash:
            self._content_hash = None
        self.save()

    @classmethod
    def dump_files(cls, debug=True, verbose=False):
        """
        Writes all files to the filesystem.
        """
        if debug:
            tmp_debug = settings.DEBUG
            settings.DEBUG = False
        try:
            q = cls.objects.only('id', 'name', '_content_hash')\
                .values_list('id', 'name', '_content_hash')
            total = q.count()
            if verbose:
                print('Checking %i total files...' % (total,))
            i = 0
            for (file_id, name, content_hash) in q.iterator():
                i += 1
                if verbose and not i % 100:
                    print('%i of %i' % (i, total))
                if not is_fresh(name=name, content_hash=content_hash):
                    if verbose:
                        print(('File %i-%s is stale. Writing to local file ' 'system...') % (file_id, name))
                    f = File.objects.get(id=file_id)
                    write_file(f.name, f.content, overwrite=True)
                    f._content_hash = None
                    f.save()
        finally:
            if debug:
                settings.DEBUG = tmp_debug
