from django.db.models import Count
from datetime import datetime

from ...simplified import simplified_modelapi, SimplifiedModelApi, PermissionDenied
from devilry.coreutils.simplified.metabases import (SimplifiedSubjectMetaMixin,
                                                   SimplifiedPeriodMetaMixin,
                                                   SimplifiedAssignmentMetaMixin,
                                                   SimplifiedAssignmentGroupMetaMixin,
                                                   SimplifiedDeadlineMetaMixin,
                                                   SimplifiedDeliveryMetaMixin,
                                                   SimplifiedStaticFeedbackMetaMixin,
                                                   SimplifiedFileMetaMetaMixin)
from devilry.apps.core.models import AssignmentGroup, Delivery



class PublishedWhereIsCandidateMixin(SimplifiedModelApi):
    """ Mixin class extended by all classes in the Simplified API for Student using the Simplified API """

    @classmethod
    def create_searchqryset(cls, user, **kwargs):
        """ Returns all objects of this type that matches arguments
        given in ``\*\*kwargs`` where ``user`` is a student.

        :param user: A django user object.
        :param \*\*kwargs: A dict containing search-parameters.
        :rtype: a django queryset
        """
        return cls._meta.model.published_where_is_candidate(user)

    @classmethod
    def read_authorize(cls, user, obj):
        """ Checks if the given ``user`` is an student in the given
        ``obj``, and raises ``PermissionDenied`` if not.

        :param user: A django user object.
        :param obj: An object of the type this method is used in.
        :throws PermissionDenied:
        """
        if not cls._meta.model.published_where_is_candidate(user).filter(id=obj.id):
            raise PermissionDenied()


@simplified_modelapi
class SimplifiedFileMeta(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.FileMeta`. """
    class Meta(SimplifiedFileMetaMetaMixin):
        """ Defines what methods a Student can use on a FileMeta object using the Simplified API """
        methods = ['search', 'read', 'create']


@simplified_modelapi
class SimplifiedDeadline(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.Deadline`. """
    class Meta(SimplifiedDeadlineMetaMixin):
        """ Defines what methods a Student can use on a Deadline object using the Simplified API """
        methods = ['search', 'read']
        editablefields = tuple()

    @classmethod
    def create_searchqryset(cls, user, **kwargs):
        return cls._meta.model.published_where_is_candidate(user).annotate(number_of_deliveries=Count('deliveries'))


@simplified_modelapi
class SimplifiedStaticFeedback(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.StaticFeedback`. """
    class Meta(SimplifiedStaticFeedbackMetaMixin):
        """ Defines what methods a Student can use on a StaticFeedback object using the Simplified API """
        methods = ['search', 'read']


@simplified_modelapi
class SimplifiedDelivery(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.Delivery`. """
    class Meta(SimplifiedDeliveryMetaMixin):
        """ Defines what methods a Student can use on a Delivery object using the Simplified API """
        methods = ['search', 'read', 'create', 'update']
        editablefields = ('successful', 'deadline')

    @classmethod
    def pre_full_clean(cls, user, obj):
        obj.time_of_delivery = datetime.now()
        candidate = obj.deadline.assignment_group.candidates.get(student=user)
        obj.delivered_by = candidate
        obj._set_number()

    @classmethod
    def write_authorize(cls, user, obj):
        """ Checks if the given ``user`` is an student in the given
        ``obj``, and raises ``PermissionDenied`` if not.

        :param user: A django user object.
        :param obj: An object of the type this method is used in.
        :throws PermissionDenied:
        """
        if not AssignmentGroup.published_where_is_candidate(user).filter(id=obj.deadline.assignment_group.id):
            raise PermissionDenied()
        if obj.id != None:
            current = Delivery.objects.get(id=obj.id)
            if current.successful:
                raise PermissionDenied()



@simplified_modelapi
class SimplifiedAssignmentGroup(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.AssignmentGroup`. """
    class Meta(SimplifiedAssignmentGroupMetaMixin):
        """ Defines what methods a Student can use on an AssignmentGroup object using the Simplified API """
        methods = ['search', 'read']


@simplified_modelapi
class SimplifiedAssignment(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.Assignment`. """
    class Meta(SimplifiedAssignmentMetaMixin):
        """ Defines what methods a Student can use on an Assignment object using the Simplified API """
        methods = ['search', 'read']


@simplified_modelapi
class SimplifiedPeriod(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.Period`. """
    class Meta(SimplifiedPeriodMetaMixin):
        """ Defines what methods a Student can use on a Period object using the Simplified API """
        methods = ['search', 'read']


@simplified_modelapi
class SimplifiedSubject(PublishedWhereIsCandidateMixin):
    """ Simplified wrapper for :class:`devilry.apps.core.models.Subject`. """
    class Meta(SimplifiedSubjectMetaMixin):
        """ Defines what methods a Student can use on a Subject object using the Simplified API """
        methods = ['search', 'read']

@@ -27,16 +27,21 @@
 rt Count
+, Max
 %0Afrom da
@@ -4863,32 +4863,520 @@
 arch', 'read'%5D%0A%0A
+    @classmethod%0A    def create_searchqryset(cls, user):%0A        %22%22%22 Returns all AssignmentGroup-objects where given %60%60user%60%60 is candidate.%0A%0A        :param user: A django user object.%0A        :rtype: a django queryset%0A        %22%22%22%0A        return cls._meta.model.published_where_is_candidate(user).annotate(latest_delivery_id=Max('deadlines__deliveries__id'),%0A                                                                           number_of_deliveries=Count('deadlines__deliveries'))%0A%0A%0A
 %0A@simplified_mod

Annotate latest_delivery and number_of_deliveries.