import json
import os
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db.models import Q
from django.conf import settings
from django.http import HttpResponse

from core.models import (Course, AnnouncementPost, AnnouncementPostAttachment, AnnouncementPostViewCount,
                         AnnouncementUpvote, UserInformation)
from announcements.serializers import AnnouncementPostSerializer
from utils import add_course_activity

# Create your views here.

class AnnouncementPostList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        course_id = request.GET.get('course_id', '')
        search_key = request.GET.get('search_key', '')
        offset = request.GET.get('offset', '0')
        limit = request.GET.get('limit', '10')
        category = request.GET.get('category', '')

        try:
            offset = int(offset)
            limit = int(limit)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # Check if user has access to the course
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(student__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        if category == 'All':
            category = [True, False]
        else:
            category = [False]

        count = AnnouncementPost.objects.filter(
                                                Q(is_published__in=category) &
                                                Q(course__id=course_id) &
                                                (Q(title__trigram_word_similar=search_key) |
                                                Q(title__icontains=search_key)) |
                                                Q(content__trigram_word_similar=search_key)).exclude(Q(is_published=False) & ~Q(user__id=request.user.id)).distinct().count()
        announcement_posts = AnnouncementPost.objects.filter(
                                                            Q(is_published__in=category) &
                                                            Q(course__id=course_id) &
                                                            (Q(title__trigram_word_similar=search_key) |
                                                            Q(title__icontains=search_key)) |
                                                            Q(content__trigram_word_similar=search_key)).exclude(Q(is_published=False) & ~Q(user__id=request.user.id)).distinct().order_by('-created_at')[offset:limit]

        serializer = AnnouncementPostSerializer(announcement_posts, many=True)

        return Response({'announcement_posts': serializer.data, 'count': count, 'current_user_id': request.user.id, 'current_user_role': user_information.role}, status=status.HTTP_200_OK)

    def post(self, request):
        course_id = request.POST.get('course_id', '')
        title = request.POST.get('title', '')
        content = request.POST.get('content', '')
        is_published = request.POST.get('is_published', '')
        attachments = request.FILES.getlist('attachments')

        if course_id == '' or title == '' or content == '':
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            course = Course.objects.get(id=course_id)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # Check if user has access to the course
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        if is_published=='true':
            is_published = True
        else:
            is_published = False

        announcement_post = AnnouncementPost.objects.create(
                                                        course=course,
                                                        user=request.user,
                                                        title=title,
                                                        content=content,
                                                        is_published=is_published)

        for a in attachments:
            AnnouncementPostAttachment.objects.create(announcement_post=announcement_post, attachment=a)

        return Response(status=status.HTTP_201_CREATED)


class AnnouncementPostDetails(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        post_id = request.GET.get('post_id', '')

        try:
            post = AnnouncementPost.objects.get(id=post_id)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Check if user has access to the course
        course_id = post.course.id
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(student__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        # Check if user has already viewed this post, if not then create the post view count object
        post_view_object = AnnouncementPostViewCount.objects.filter(Q(user=request.user) & Q(announcement_post=post))
        if post_view_object.exists() is False:
            AnnouncementPostViewCount.objects.create(user=request.user, announcement_post=post)

        serializer = AnnouncementPostSerializer(post, context={'request_user': request.user})

        return Response({'post_data': serializer.data, 'current_user_id': request.user.id, 'current_user_role': user_information.role}, status=status.HTTP_200_OK)

    def put(self, request):
        post_id = request.data.get('post_id', '')
        title = request.data.get('title', '')
        content = request.data.get('content', '')
        old_attachments = json.loads(request.data.get('old_attachments', ''))
        new_attachments = request.FILES.getlist('new_attachments')

        # Remove everything before and including '/media/' substring.
        # Replace all '%20' substring in directory name with empty space ' '.
        # Postgres database does not convert empty space ' ' in directory name into '%20'.
        # So we cannot have '%20' in directory names.
        try:
            for index, a in enumerate(old_attachments):
                a = a.split('/media/', 1)[1]
                old_attachments[index] = os.path.dirname(a).replace('%20', ' ') + '/' + os.path.basename(a)
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            post = AnnouncementPost.objects.get(id=post_id)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Check if user has access to the course
        course_id = post.course.id
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        if request.user != post.user:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        if title == '' or content == '':
            return Response(status=status.HTTP_400_BAD_REQUEST)

        post.title = title
        post.content = content
        post.is_edited = True
        post.save()

        old_stored_attachments = post.attachments.all()
        for a in old_stored_attachments:
            if a.attachment not in old_attachments:
                a.delete()

        for a in new_attachments:
            AnnouncementPostAttachment.objects.create(announcement_post=post, attachment=a)

        return Response(status=status.HTTP_200_OK)

    def delete(self, request):
        post_id = request.data.get('post_id', '')

        if post_id == '':
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            post = AnnouncementPost.objects.get(id=post_id)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Check if user has access to the course
        course_id = post.course.id
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        if user_information.role=='Student' or post.user.id!=user_information.user.id:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        post.delete()

        return Response(status=status.HTTP_200_OK)


class AnnouncementPostPublishView(APIView):
    permission_classes = [IsAuthenticated]

    def put(self, request):
        course_id = request.data.get('course_id', '')
        post_id = request.data.get('post_id', '')

        if course_id=='' or post_id=='':
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            post = AnnouncementPost.objects.get(id=post_id)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Check if user has access to the course
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        if request.user != post.user:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        if post.is_published is False:
            post.is_published = True
        else:
            post.is_published = False
        post.save()

        return Response(status=status.HTTP_200_OK)


class AnnouncementUpvoteView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        post_id = request.data.get('post_id', '')

        if post_id == '':
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            post = AnnouncementPost.objects.get(id=post_id)
            user_information = UserInformation.objects.get(user=request.user)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Check if user has access to the course
        course_id = post.course.id
        if user_information.role == 'Instructor':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(student__id=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        post_upvote = AnnouncementUpvote.objects.filter(Q(user=request.user) & Q(announcement_post=post))

        if post_upvote.exists():
            post_upvote.delete()
        else:
            AnnouncementUpvote.objects.create(user=request.user, announcement_post=post)

        add_course_activity(course_id, request.user.id, 'participation')

        return Response(status=status.HTTP_200_OK)
