"""
Django Model baseclass for database-backed configuration.
"""
from django.db import models
from django.contrib.auth.models import User
from django.core.cache import get_cache, InvalidCacheBackendError

try:
    cache = get_cache('configuration')  # pylint: disable=invalid-name
except InvalidCacheBackendError:
    from django.core.cache import cache


class ConfigurationModel(models.Model):
    """
    Abstract base class for model-based configuration

    Properties:
        cache_timeout (int): The number of seconds that this configuration
            should be cached
    """

    class Meta(object):  # pylint: disable=missing-docstring
        abstract = True

    # The number of seconds
    cache_timeout = 600

    change_date = models.DateTimeField(auto_now_add=True)
    changed_by = models.ForeignKey(User, editable=False, null=True, on_delete=models.PROTECT)
    enabled = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        """
        Clear the cached value when saving a new configuration entry
        """
        super(ConfigurationModel, self).save(*args, **kwargs)
        cache.delete(self.cache_key_name())

    @classmethod
    def cache_key_name(cls):
        """Return the name of the key to use to cache the current configuration"""
        return 'configuration/{}/current'.format(cls.__name__)

    @classmethod
    def current(cls):
        """
        Return the active configuration entry, either from cache,
        from the database, or by creating a new empty entry (which is not
        persisted).
        """
        cached = cache.get(cls.cache_key_name())
        if cached is not None:
            return cached

        try:
            current = cls.objects.order_by('-change_date')[0]
        except IndexError:
            current = cls()

        cache.set(cls.cache_key_name(), current, cls.cache_timeout)
        return current

    @classmethod
    def is_enabled(cls):
        """Returns True if this feature is configured as enabled, else False."""
        return cls.current().enabled
