"""Module defining base django models linked to redis ones"""

from django.db import models
from django.utils.functional import cached_property


class RedisBackedDjangoModel(models.Model):
    """A mixin for django models to associate an instance.

    Attributes
    ----------
    redis_model : a Limpyd model class
        To avoid recursive imports, this may be defined in a
        ``cached_property``.

    Example
    -------
    >>> from django.db import models
    >>> from django.utils.functional import cached_property
    >>>
    >>> from mtp.apps.example.limpyd_models import ExampleModelData
    >>> from mtp.apps.common.limpyd_base.django_models import RedisBackedDjangoModel
    >>>
    >>> class ExampleModel(RedisBackedDjangoModel, models.Model):
    ...     redis_model = ExampleModelData
    ...
    ...     some_field = models.CharField(max_length=255)
    ...
    ...     @cached_property
    ...     def redis_model(self):
    ...         '''Other way to define ``redis_model``'''
    ...
    ...         from mtp.apps.example.limpyd_models import ExampleModelData
    ...         return ExampleModelData
    ...

    """

    redis_model = None

    class Meta:
        abstract = True  # it's an abstract base model class

    @cached_property
    def redis_instance(self):
        """Return the limpyd model instance tied to this django instance, creating it if needed.

        It's a cached property, so this will only be evaluated once for an instance of this class.

        Returns
        -------
        Limpyd model instance
            The instance of the limpyd model defined by ``redis_model`` tied to the
            current django model instance.

        Raises
        ------
        limpyd.exceptions.DoesNotExist
            When no instances of the limpyd model exists with the ``pk`` of
            the current django model instance.

        Example
        -------
        >>> my_django_instance.redis_instance.do_something()

        Notes
        -----
        Both instances share the same value for their primary key so this is
        just a simple object fetching.

        """

        result, __ = self.redis_model.get_or_connect(pk=self.pk)
        return result


class RedisBackedDjangoModelWithLogs(RedisBackedDjangoModel):
    """A mixin for django models to associate a limpyd instance.

    Use it with the ``RedisBackedDjangoModel`` base.

    This base model offer a ``logger`` property with logging capabilities.

    """

    class Meta:
        abstract = True  # it's an abstract base model class

    @property
    def logger(self):
        """Alias for the redis limpyd instance

        So we can do something like that:
        >>> django_instance.logger.info('Info message')

        """

        return self.redis_instance
