"""
Manage related users.
"""
from django.db.models import Q
from djangorestframework.resources import ModelResource
from djangorestframework.views import ListOrCreateModelView
from djangorestframework.views import InstanceModelView
from djangorestframework.permissions import IsAuthenticated

from devilry.apps.core.models import RelatedExaminer
from devilry.apps.core.models import RelatedStudent

from .auth import IsPeriodAdmin
from .mixins import SelfdocumentingMixin
from .log import logger




class IsPeriodAdminPeriodIdKwarg(IsPeriodAdmin):
    ID_KWARG = 'period_id'


class RelatedUserResource(ModelResource):
    fields = ('id', 'period', 'user', 'tags')

    def user(self, instance):
        if isinstance(instance, self.model):
            user = instance.user
            return {'email': user.email,
                    'username': user.username,
                    'id': user.id,
                    'full_name': user.devilryuserprofile.full_name}

    def period(self, instance):
        if isinstance(instance, self.model):
            return instance.period_id


class ListRelatedUsersRestMixin(SelfdocumentingMixin):
    def get_period_id(self): # Overridden in ListRelatedUsersOnAssignmentMixin
        return self.kwargs['period_id']

    def get_queryset(self):
        period_id = self.get_period_id()
        qry = self.resource.model.objects.filter(period=period_id)
        qry = qry.select_related('user', 'user__devilryuserprofile')

        querystring = self.request.GET.get('query', '')
        if len(querystring) > 0:
            qry = qry.filter(Q(user__username__icontains=querystring) |
                             Q(user__email__icontains=querystring) |
                             Q(user__devilryuserprofile__full_name__icontains=querystring) |
                             Q(tags__icontains=querystring))

        qry = qry.order_by('user__devilryuserprofile__full_name')
        return qry

    def get(self, request, **kwargs): # NOTE: We take **kwargs because this method is called with period_id or assignment_id(subclass), however it only uses ``request`` (the kwarg is used by permission handlers)
        """
        Get a list of related users. Each entry in the list is a dict/object
        with the following attributes:
        {responsetable}
        """
        return super(ListRelatedUsersRestMixin, self).get(request)

    def postprocess_get_docs(self, docs):
        responsetable = self.htmlformat_response_from_fields()
        return docs.format(modelname=self.resource.model.__name__,
                           responsetable=responsetable)


class CreateRelatedUserRestMixin(SelfdocumentingMixin):

    def post(self, request, period_id):
        """
        Create a {modelname}.

        # Parameters
        {parameterstable}

        # Returns
        {responsetable}
        """
        result = super(CreateRelatedUserRestMixin, self).post(request)
        created = result.cleaned_content
        logger.info('User=%s created %s with id=%s (user_id=%s, tags=%s)', self.user,
                    self.resource.model.__name__, created.id, created.user_id,
                    created.tags)
        return result

    def postprocess_post_docs(self, docs):
        responsetable = self.htmlformat_response_from_fields()
        parameterstable = self.htmlformat_parameters_from_form(override_helptext={'user': 'The ID of the related user.'})
        return docs.format(modelname=self.resource.model.__name__,
                           parameterstable=parameterstable,
                           responsetable=responsetable)


class InstanceRelatedUserRestBaseView(SelfdocumentingMixin, InstanceModelView):
    permissions = (IsAuthenticated, IsPeriodAdminPeriodIdKwarg)

    def put(self, request, period_id, id):
        """
        Update the {modelname}.

        # Parameters
        {parameterstable}

        # Returns
        {responsetable}
        """
        result = super(InstanceRelatedUserRestBaseView, self).put(request, id)
        logger.info('User=%s updated %s with id=%s (user_id=%s, tags=%s)', self.user,
                    self.resource.model.__name__, id, result.user_id, result.tags)
        return result

    def delete(self, request, period_id, id):
        """
        Delete the {modelname}.

        # Response
        Status 204, with empty body on success.
        """
        userid = self.get_instance().user_id
        result = super(InstanceRelatedUserRestBaseView, self).delete(request, id)
        logger.info('User=%s deleted %s with id=%s (user_id=%s)', self.user,
                    self.resource.model.__name__, id, userid)
        return result

    def postprocess_docs(self, docs):
        responsetable = self.htmlformat_response_from_fields()
        parameterstable = self.htmlformat_parameters_from_form()
        return docs.format(modelname=self.resource.model.__name__,
                           parameterstable=parameterstable,
                           responsetable=responsetable)


#############################
# Examiner
#############################

class RelatedExaminerResource(RelatedUserResource):
    model = RelatedExaminer


class ListOrCreateRelatedExaminerRest(CreateRelatedUserRestMixin, ListRelatedUsersRestMixin,
                                      ListOrCreateModelView):
    resource = RelatedExaminerResource
    permissions = (IsAuthenticated, IsPeriodAdminPeriodIdKwarg)


class InstanceRelatedExaminerRest(InstanceRelatedUserRestBaseView):
    resource = RelatedExaminerResource



#############################
# Student
#############################

class RelatedStudentResource(RelatedUserResource):
    model = RelatedStudent
    fields = RelatedUserResource.fields + ('candidate_id',)

class ListOrCreateRelatedStudentRest(CreateRelatedUserRestMixin, ListRelatedUsersRestMixin,
                                     ListOrCreateModelView):
    resource = RelatedStudentResource
    permissions = (IsAuthenticated, IsPeriodAdminPeriodIdKwarg)


class InstanceRelatedStudentRest(InstanceRelatedUserRestBaseView):
    """
    Read, update and delete a single related student.
    """
    resource = RelatedStudentResource

@@ -2146,32 +2146,324 @@
 rs)%0A        %22%22%22%0A
+        Without the %60%60query%60%60 parameter, list all users.%0A%0A        ## Parameters%0A        Use the %60%60query%60%60 parameter in the querystring to search for users by:%0A%0A        - Full name%0A        - Username%0A        - Email%0A        - Tags%0A%0A        Uses case-ignore-contains search.%0A%0A        # Returns%0A
         Get a li

Document query.