"""Module holding redis models for the ``workshops`` app."""

from statistics import mean, StatisticsError

from limpyd_extensions.dynamic.fields import DynamicSortedSetField
from limpyd_extensions.dynamic.model import ModelWithDynamicFieldMixin

from mtp.apps.common.limpyd_base import DjangoBackedRedisModel

from .models import Workshop as DjangoWorkshop


class Workshop(ModelWithDynamicFieldMixin, DjangoBackedRedisModel):
    """Workshop redis model for the ``Workshop`` django model

    Attributes
    ----------
    scores_for_session: DynamicSortedSetField
        A SortedSet for each session (session pk).
        Keys are a token representing session+user (see ``get_score_key``)
        Score are the computed scores for the current object.

    """

    django_model = DjangoWorkshop

    scores_for_session = DynamicSortedSetField()

    @staticmethod
    def get_score_key(session_id, user_id, question_id):
        """Return the key to uses as key in``scores_for_session``.

        It uniquely identify a score for a user during a training session.

        Parameters
        ----------
        session_id: str
            The uuid of the session
        user_id: str
            The uuid of the user
        question_id: str
            The uuid of the question

        Example
        -------

        >>> sorted_set = self.scores_for_session(session.pk)
        >>> key = self.get_score_key(session.pk, user.pk, question.id)
        >>> sorted_set.zadd(score, key)

        Notes
        -----
        We could have used a hash of the string to reduce the memory footprint, but it's easier
        this way to debug data when checking directly in redis.

        """

        return '%s:%s:%s' % (session_id, user_id, question_id)

    def save_trainee_score(self, session_id, user_id, question_id, score):
        """Save the given score for a given session and trainee

        Parameters
        ----------
        session_id: str
            The uuid of the session the score was recorded into
        user_id: str
            The uuid of the user who did the score
        question_id: str
            The uuid of the question the score was obtained for
        score: int
            The score we want to save

        """

        score_set = self.scores_for_session(session_id)
        score_key = self.get_score_key(session_id, user_id, question_id)

        score_set.zadd(score, score_key)

    def get_trainee_score(self, session_id, user_id, question_id):
        """Get the score of a given trainee for a given session

        Parameters
        ----------
        session_id: str
            The uuid of the session the score was recorded into
        user_id: str
            The uuid of the user we want the score
        question_id: list(str)
            The uuid of the question we want the score

        Returns
        -------
        int or None
            The score for this session / trainee / question
            or None if no score was found.

        """

        score_set = self.scores_for_session(session_id)
        score_key = self.get_score_key(session_id, user_id, question_id)

        return score_set.zscore(score_key)

    def get_average_session_score(self, session_id):
        """Get the average score for this given session

        Parameters
        ----------
        session_id: str
            The uuid of the session we want the average score

        Returns
        -------
        int
            The average score for this session

        """

        score_set = self.scores_for_session(session_id)

        try:
            return mean(dict(score_set.zrange(0, -1, withscores=True)).values())
        except StatisticsError:
            return 0


