import logging
import os

from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext_lazy

from core.fields import IntegerField
from core.utils import dtnow
from storage.enums import CrcType
from storage.services import verify_file_from_json, get_json_crc

_log = logging.getLogger(__name__)

MEDIA_ROOT = settings.MEDIA_ROOT


def get_storage_path(instance, file_name):
    """ Get file name for storage
    :param instance: DataStorage record to save
    :param file_name: Original file name
    :return: String with filename
    """
    path_no_ext, ext = os.path.splitext(file_name)
    return '{0}/{1}/{2}/{3}_{4}{5}'.format(
        instance.user,
        instance.type,
        instance.format,
        path_no_ext,
        instance.created.strftime('%Y%m%d%H%M%S'),
        ext
    )


class DataStorage(models.Model):
    """ One record in storage """

    class Type(models.IntegerChoices):
        UNKNOWN = 0, gettext_lazy('Unknown')
        DB_DUMP = 1, gettext_lazy('DB dump')
        CSV_EXPORT = 2, gettext_lazy('CSV export')
        JSON_EXPORT = 3, gettext_lazy('JSON export')
        CLAMAV = 4, gettext_lazy('ClamAV updates')
        FIREWALL = 5, gettext_lazy('Firewall')

    class Format(models.IntegerChoices):
        UNKNOWN = 0, gettext_lazy('Unknown')
        PLAIN = 1, gettext_lazy('Plain')
        JSON = 2, gettext_lazy('JSON')
        CSV = 3, gettext_lazy('CSV')
        ZIP = 4, gettext_lazy('ZIP')
        TAR = 5, gettext_lazy('TAR')
        XML = 6, gettext_lazy('XML')

    type = IntegerField(choices=Type.choices,
                        verbose_name=gettext_lazy('Type'),
                        help_text=gettext_lazy('Type of storage record'),
                        default=Type.UNKNOWN)
    format = IntegerField(choices=Format.choices,
                          verbose_name=gettext_lazy('Format'),
                          help_text=gettext_lazy('Format of storage record'),
                          default=Format.UNKNOWN)
    created = models.DateTimeField(auto_now_add=True,
                                   verbose_name=gettext_lazy('Created'),
                                   help_text=gettext_lazy('Date and time, when record was created'))
    last_access = models.DateTimeField(auto_now=True,
                                       verbose_name=gettext_lazy('Last access'),
                                       help_text=gettext_lazy('Date and time, when record was downloaded last time'))
    user = models.ForeignKey(User,
                             on_delete=models.CASCADE,
                             verbose_name=gettext_lazy('User'),
                             help_text=gettext_lazy('User, who own this record'))
    size = IntegerField(verbose_name=gettext_lazy('Size'),
                        help_text=gettext_lazy('Size of record in MB'),
                        min_value=0)
    crc = models.JSONField(verbose_name=gettext_lazy('CRC'),
                           help_text=gettext_lazy('Checksum of record'),
                           blank=True, null=True)
    description = models.TextField(null=True,
                                   blank=True,
                                   verbose_name=gettext_lazy('Description'),
                                   help_text=gettext_lazy('Description'))
    free_date = models.DateField(verbose_name=gettext_lazy('Remove date'),
                                 help_text=gettext_lazy('When record will be removed'),
                                 blank=True, null=True)
    file = models.FileField(upload_to=get_storage_path,
                            verbose_name=gettext_lazy('File'),
                            help_text=gettext_lazy('Actual file name'))

    def get_full_path(self):
        return os.path.join(MEDIA_ROOT, self.file.name)

    def update_crc(self):
        self.crc = get_json_crc(self.get_full_path(), CrcType.SHA512)
        self.save()

    def verify_file(self):
        try:
            return verify_file_from_json(self.get_full_path(), self.crc)

        except KeyError:
            return False

        except TypeError:
            _log.error(f"Can't calculate crc for {self.file} crc is {self.crc}")
            return False

        except Exception as e:
            _log.error(e)
            return False

    def save(self, *args, **kwargs):
        self.last_access = dtnow()
        super().save(*args, **kwargs)
