from django.shortcuts import HttpResponse, get_object_or_404, render, redirect
from django.views.generic import View, DetailView
from django.core.urlresolvers import reverse_lazy
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.conf import settings
from django.urls import reverse
from notifications.models import Notification
from iconolab.models import Collection, Annotation, IconolabComment, Image, MetaCategoriesCountInfo
from iconolab.auth.forms import UserForm
from uuid import UUID
import logging

logger = logging.getLogger(__name__)

class UserHomeView(DetailView):
    """
        Homepage for user account, displays latest unread notifications, latest annotations created recap, latest contributions on annotations recap,
        latest annotations commented recap, also provides access to admin interface.
    """
    model = User
    slug_field = 'id'

    def get_context_data(self, **kwargs):
        context = super(UserHomeView, self).get_context_data(**kwargs)
        profile_user = self.object
        context['profile_user'] = profile_user
        context['user_annotations'] = Annotation.objects.filter(author=profile_user).prefetch_related(
            'current_revision',
            'revisions',
            'image',
            'image__item',
            'image__item__collection'
        ).order_by("-created")[:5]
        context['user_contributed_annotations'] = Annotation.objects.get_annotations_contributed_for_user(profile_user)[:5]
        context['user_commented_annotations'] = Annotation.objects.get_annotations_commented_for_user(profile_user)[:5]
        # .exclude(annotation_guid__in=[annotation.annotation_guid for annotation in context['user_revisions_annotations']])

        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data()
        context['user_form'] = UserForm(instance=request.user)

        if request.user.is_authenticated() and self.object == request.user:
            if request.GET.get('clear_notifications', False):
                Notification.objects.filter(recipient=request.user).mark_all_as_read()
            logger.debug(Notification.objects.filter(recipient=request.user))
            context['notifications'] = Notification.objects.filter(recipient=request.user)

        return render(request, 'iconolab/user_home.html', context)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data()

        user_form = UserForm(data=request.POST, instance=request.user)
        context['user_form'] = user_form

        if request.user.is_authenticated() and self.object == request.user:
            if user_form.is_valid():
                user = user_form.save(commit=False)
                user.save()
                return redirect(reverse('user_home', kwargs={'slug': user.id}))

        return render(request, 'iconolab/user_home.html', context)

class UserNotificationsView(View):
    """
        View that displays the notifications the user received
    """
    def get(self, request, *args, **kwargs):
        context = {}
        notifications = Notification.objects.filter(recipient=request.user)
        context['notifications_unread_ids'] = notifications.unread().values_list('id', flat=True)
        page = request.GET.get('page', 1)
        paginator = Paginator(notifications, 50)
        try:
            notifications_list = paginator.page(page)
        except PageNotAnInteger:
            notifications_list = paginator.page(1)
        except EmptyPage:
            notifications_list = paginator.page(paginator.num_pages)
        context['notifications'] = notifications_list
        return render(request, 'iconolab/user_notifications.html', context)

class UserAnnotationsView(DetailView):
    """
        View that displays the full paginated list of annotations created for the considered user
    """
    model = User
    slug_field = 'id'

    def get_context_data(self, **kwargs):
        context = super(UserAnnotationsView, self).get_context_data(**kwargs)
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        profile_user = self.object
        context = self.get_context_data()
        page = request.GET.get('page', 1)
        per_page=request.GET.get('perpage', 10)
        paginator = Paginator(Annotation.objects.filter(author=profile_user).prefetch_related(
            'current_revision',
            'revisions',
            'image',
            'image__item',
            'image__item__collection'
        ).order_by("-created").all(), per_page)
        try:
            annotations_list = paginator.page(page)
        except PageNotAnInteger:
            annotations_list = paginator.page(1)
        except EmptyPage:
            annotations_list = paginator.page(paginator.num_pages)
        context['user_annotations'] = annotations_list
        context['profile_user'] = profile_user
        return render(request, 'iconolab/user_annotations.html', context)

class UserCommentedView(DetailView):
    """
        View that displays the full paginated list of annotations on which the considered user has commented
    """
    model = User
    slug_field = 'id'

    def get_context_data(self, **kwargs):
        context = super(UserCommentedView, self).get_context_data(**kwargs)
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        profile_user = self.object
        context = self.get_context_data()
        page = request.GET.get('page', 1)
        per_page=request.GET.get('perpage', 10)
        paginator = Paginator(Annotation.objects.get_annotations_commented_for_user(profile_user), per_page)
        try:
            contributions_list = paginator.page(page)
        except PageNotAnInteger:
            contributions_list = paginator.page(1)
        except EmptyPage:
            contributions_list = paginator.page(paginator.num_pages)
        context['user_commented_annotations'] = contributions_list
        context['profile_user'] = profile_user
        return render(request, 'iconolab/user_commented.html', context)

class UserContributedView(DetailView):
    """
        View that displays the full paginated list of annotations on which the considered user has submitted at least one revision
    """
    model = User
    slug_field = 'id'

    def get_context_data(self, **kwargs):
        context = super(UserContributedView, self).get_context_data(**kwargs)
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        profile_user = self.object
        context = self.get_context_data()
        page = request.GET.get('page', 1)
        per_page=request.GET.get('perpage', 10)
        paginator = Paginator(Annotation.objects.get_annotations_contributed_for_user(profile_user), per_page)
        try:
            commented_list = paginator.page(page)
        except PageNotAnInteger:
            commented_list = paginator.page(1)
        except EmptyPage:
            commented_list = paginator.page(paginator.num_pages)
        context['user_contributed_annotations'] = commented_list
        context['profile_user'] = profile_user
        return render(request, 'iconolab/user_contributed.html', context)

class UserCollectionAdminView(DetailView):
    """
        View that displays the admin panel, allowing collection admin to filter and order annotations on several criterias
    """
    model = User
    slug_field = 'id'

    def get_context_data(self, **kwargs):
        context = super(UserCollectionAdminView, self).get_context_data(**kwargs)
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        profile_user = self.object
        context = self.get_context_data()
        collection_name = kwargs.get("collection_name")
        collection_qs = Collection.objects.filter(name=collection_name)
        if not request.user.is_staff and not request.user.is_authenticated or profile_user != request.user or not collection_qs.exists():
            return redirect(reverse_lazy('user_home', kwargs={'slug': profile_user.id}))
        collection = collection_qs.first()
        if collection not in profile_user.profile.managed_collections.all():
            return redirect(reverse_lazy('user_home', kwargs={'slug': profile_user.id}))

        annotation_queryset = Annotation.objects.distinct().filter(image__item__collection=collection).prefetch_related('current_revision', 'stats', 'image', 'image__item')

        # filtering
        comments_count_filter = request.GET.get("min_comments", "")
        if comments_count_filter and comments_count_filter.isdigit():
            comments_count_filter = int(comments_count_filter)
            context["qarg_min_comments"] = comments_count_filter
            annotation_queryset = annotation_queryset.filter(stats__comments_count__gte=comments_count_filter)
        revisions_count_filter = request.GET.get("min_revisions", "")
        if revisions_count_filter and revisions_count_filter.isdigit():
            revisions_count_filter = int(revisions_count_filter)
            context["qarg_min_revisions"] = revisions_count_filter
            annotation_queryset = annotation_queryset.filter(stats__submitted_revisions_count__gte=revisions_count_filter)
        relevancy_filter = request.GET.get("min_relevancy", "")
        if relevancy_filter and relevancy_filter.isdigit():
            min_relevancy = min(int(relevancy_filter), 5)
            context["qarg_min_relevancy"] = relevancy_filter
            annotation_queryset = annotation_queryset.filter(current_revision__tagginginfo__relevancy__gte=min_relevancy)
        accuracy_filter = request.GET.get("min_accuracy", "")
        if accuracy_filter and accuracy_filter.isdigit():
            min_accuracy = min(int(accuracy_filter), 5)
            context["qarg_min_accuracy"] = min_accuracy
            annotation_queryset = annotation_queryset.filter(current_revision__tagginginfo__accuracy__gte=min_accuracy)

        metacategories_filter = []
        mtcg_annotations_ids = {}
        filtering_on_metacategories = False
        context["qarg_metacategories_filters"] = {}
        for metacategory in collection.metacategories.all():
            # Default filter is 0
            mtcg_filter = request.GET.get("min_metacategory_"+str(metacategory.id), "0")
            # We ignore filters that aren't integers
            if mtcg_filter and mtcg_filter.isdigit():
                # For each metacategory we have a dict entry with key=id that will be a list of the annotation matching the filter
                mtcg_annotations_ids[str(metacategory.id)] = []
                # Queryarg for autocompleting the form on page load
                context["qarg_metacategories_filters"]["min_metacategory_"+str(metacategory.id)] = mtcg_filter
                # If we got this far we did a filter on metacategories
                filtering_on_metacategories = True
                for annotation in annotation_queryset.all():
                    if int(mtcg_filter) == 0 or MetaCategoriesCountInfo.objects.filter(metacategory=metacategory, annotation_stats_obj=annotation.stats, count__gte=int(mtcg_filter)).exists():
                         mtcg_annotations_ids[str(metacategory.id)].append(annotation.annotation_guid)
        if filtering_on_metacategories:
            # If we did a filter on metacategories we have several list of matching annotations. We only display the intersection of all these lists.
            annotation_queryset = annotation_queryset.filter(annotation_guid__in=
                list(
                     set.intersection(*[
                        set(value) for value in list(mtcg_annotations_ids.values())
                    ])
                )
            )

        # ordering
        ordering = []
        orderby_map = {
            "oldest": "created",
            "recent": "-created",
            "most_commented": "-stats__comments_count",
            "most_tagged": "-stats__tag_count",
            "most_revised": "-stats__submitted_revisions_count",
            "most_viewed": "-stats__views_count"
        }
        for ordering_qarg in ["first", "second", "third", "fourth"]:
            if request.GET.get(ordering_qarg, "") in ["oldest", "recent", "most_commented", "most_tagged", "most_revised", "most_viewed"] and orderby_map.get(request.GET.get(ordering_qarg)) not in ordering:
                context["qarg_"+ordering_qarg] = request.GET.get(ordering_qarg)
                ordering.append(orderby_map.get(request.GET.get(ordering_qarg)))
        annotation_queryset = annotation_queryset.order_by(*ordering)
        context["collection_filtered_annotations"] = annotation_queryset
        context["collection"] = collection
        logger.debug(ordering)
        logger.debug(annotation_queryset)
        return render(request, 'iconolab/user_collection_admin.html', context)
