"""This module holds the managers for the ``workshops`` app."""

from django.db import models
from django.db.models import Sum

from mtp.discrete_apps.versionable.managers import (
    PolymorphicManagerForDependency,
    PolymorphicQuerySetForDependency,
)

from mtp.apps.common.managers import CleanDuplicatedManagerMixin
from mtp.apps.assessments.managers.activities import AssessableQuerySet
from mtp.apps.sync.managers import SyncableManager, SyncableQuerySet


class DependencyWorkshopStepQuerySet(AssessableQuerySet,
                                     SyncableQuerySet,
                                     PolymorphicQuerySetForDependency):
    """QuerySet for the ``mtp.apps.workshops.models.WorkshopStep`` model"""

    def for_workshop(self, workshop):
        """Filter only steps steps who belongs to the given workshop.

        Parameters
        ----------
        workshop : mtp.apps.workshop.models.Workshop
            The workshop we want the steps from.

        Returns
        -------
        TrainingQueryset
            A clone of the original queryset (``self``), filtered.

        """

        return self.filter(workshop=workshop)

    def assessing(self):
        """Filter only assessing models.

        All WorkshopStep are assessing if the workshop is assessing

        Returns
        -------
        Queryset of assessing models.

        """
        return self.filter(workshop__is_assessing=True)

    def non_assessing(self):
        """Filter only non-assessing models.

        All WorkshopStep are non-assessing if the workshop is non-assessing

        Returns
        -------
        Queryset of non-assessing models.

        """
        return self.filter(workshop__is_assessing=False)


class DependencyWorkshopStepManager(
        PolymorphicManagerForDependency.from_queryset(DependencyWorkshopStepQuerySet)
    ):
    """Manager for the ``mtp.apps.workshops.models.WorkshopStep`` model"""
    pass


class DependencyWorkshopStepQuestionQuerySet(AssessableQuerySet,
                                             SyncableQuerySet,
                                             PolymorphicQuerySetForDependency):
    """QuerySet for the ``mtp.apps.workshops.models.WorkshopStepQuestion`` model"""

    pass


class DependencyWorkshopStepQuestionManager(
        PolymorphicManagerForDependency.from_queryset(DependencyWorkshopStepQuestionQuerySet)
    ):
    """Manager for the ``mtp.apps.workshops.models.WorkshopStep`` model"""
    pass


class WorkshopStepQuestionAnswerManager(models.Manager):
    """Manager for the ``mtp.apps.workshops.models.WorkshopStepQuestionAnswer`` model"""
    pass


class WorkshopStepQuestionAnswerQuerySet(SyncableQuerySet, models.QuerySet):
    """QuerySet for the ``mtp.apps.workshops.models.WorkshopStepQuestionAnswer`` model"""

    def aggregate_points(self):
        """Return the points sum of answers in the queryset.

        Returns
        -------
        int
            The points sum.

        """
        return self.aggregate(Sum('points'))['points__sum'] or 0


class WorkshopStepQuestionUserAnswerQuerySet(SyncableQuerySet, models.QuerySet):
    """QuerySet for the ``mtp.apps.workshops.models.WorkshopStepQuestionUserAnswer`` model"""

    def aggregate_points(self):
        """Return the points sum of user answers in the queryset.

        Returns
        -------
        int
            The points sum.

        """
        return self.aggregate(Sum('answer__points'))['answer__points__sum'] or 0


class WorkshopStepQuestionUserAnswerManager(
        CleanDuplicatedManagerMixin,
        SyncableManager.from_queryset(WorkshopStepQuestionUserAnswerQuerySet)):
    """Manager for the ``mtp.apps.workshops.models.WorkshopStepQuestionUserAnswer`` model"""

    use_in_migrations = True

    def get_open_answer_for_question(self, question, training_session, trainee):
        """Return the "open" answer for a given question

        Parameters
        ----------
        question: ``WorkshopStepQuestion`` instance
            The question we want the answer for.
        training_session: ``TrainingSession`` instance
            The training session in the answer was written.
        trainee: ``MTPUser`` instance
            The author of the answer.

        Returns
        -------
        ``WorkshopStepQuestionUserAnswer`` instance
        or None if the provided answer is not an "open" one.

        Raises
        ------
        ``MultipleObjectsReturned`` / ``DoesNotExist``
            If multiple answers were found, or if the answer don't exist

        """

        if not question.is_open:
            return None

        return self.get(
            user=trainee,
            answer=None,
            training_session=training_session,
            question=question
        )
