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, DiscussionPost, DiscussionReply, DiscussionUpvote, UserCourse, UserInformation, 
                            DiscussionPostAttachment, DiscussionReplyAttachment, DiscussionUpvote, DiscussionPostViewCount, Instructor)
from discussion.serializers import DiscussionPostSerializer, DiscussionReplySerializer

# Create your views here.

class DiscussionPostList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        course_section = request.GET.get('course_section', '')
        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':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=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 = DiscussionPost.objects.filter(
                                                (Q(usercourse__id=course_section) &
                                                (Q(title__trigram_word_similar=search_key) | 
                                                Q(title__icontains=search_key)) |
                                                Q(content__trigram_word_similar=search_key) |
                                                Q(discussion_replies__content__trigram_word_similar=search_key)) &
                                                Q(is_published__in=category)).exclude(Q(is_published=False) & ~Q(user__id=request.user.id)).distinct().count()
        discussion_posts = DiscussionPost.objects.filter(
                                                            (Q(usercourse__id=course_section) &
                                                            (Q(title__trigram_word_similar=search_key) | 
                                                            Q(title__icontains=search_key)) |
                                                            Q(content__trigram_word_similar=search_key) |
                                                            Q(discussion_replies__content__trigram_word_similar=search_key)) &
                                                            Q(is_published__in=category)).exclude(Q(is_published=False) & ~Q(user__id=request.user.id)).distinct().order_by('-created_at')[offset:limit]
        
        serializer = DiscussionPostSerializer(discussion_posts, many=True, context={'request_user': request.user})

        return Response({'discussion_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_section = request.data.get('course_section', '')
        title = request.data.get('title', '')
        content = request.data.get('content', '')
        is_published = request.data.get('is_published', '')
        attachments = request.data.getlist('attachments')
        if UserCourse.objects.filter(id=course_section).exists():

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

            try:
                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':
                instructor_id = Instructor.objects.get(user=request.user)
                course_access = UserCourse.objects.filter(
                                                        Q(id=course_section) &
                                                        Q(instructor=instructor_id)).exists()
                
                if course_access is False:
                    return Response(status=status.HTTP_401_UNAUTHORIZED)
                    
            elif user_information.role == 'Student':
                course_access = UserCourse.objects.filter(
                                                        Q(id=course_section) &
                                                        Q(user=user_information.user.id)).exists()

                if course_access is False:
                    return Response({'Has no Access'},status=status.HTTP_401_UNAUTHORIZED)

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

            course_section = UserCourse.objects.get(id=course_section)

            discussion_post = DiscussionPost.objects.create(
                                                            usercourse=course_section, 
                                                            user=request.user,
                                                            title=title,
                                                            content=content,
                                                            is_published=is_published)

            for a in attachments:
                DiscussionPostAttachment.objects.create(discussion_post=discussion_post, attachment=a)


            return Response({"message": "Create Successfuly"},status=status.HTTP_201_CREATED)
        else: 
            return Response({'Invalid Section'},status=status.HTTP_401_UNAUTHORIZED)


class DiscussionPostDetails(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        post_id = request.GET.get('post_id', '')
        
        try:
            post = DiscussionPost.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_section = post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=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 = DiscussionPostViewCount.objects.filter(Q(user=request.user) & Q(discussion_post=post))
        if post_view_object.exists() is False:
            DiscussionPostViewCount.objects.create(user=request.user, discussion_post=post)    

        serializer = DiscussionPostSerializer(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 = DiscussionPost.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_section = post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=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:
            DiscussionPostAttachment.objects.create(discussion_post=post, attachment=a)

        return Response({'Updateed Successfully'},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 = DiscussionPost.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_section = post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
            else:
                post.delete()
                return Response({'Post Deleted Successfully'},status=status.HTTP_200_OK)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=user_information.user.id)).exists()

            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
            else:
                post.delete()
                return Response({'Post Deleted Successfully'},status=status.HTTP_200_OK)
        elif user_information.role == 'Admin':
            post.delete()
            return Response({'Post Deleted Successfully'},status=status.HTTP_200_OK)
        else:
            return Response({'Unauthorized'},status=status.HTTP_401_UNAUTHORIZED)




class DiscussionPostPublishView(APIView):
    permission_classes = [IsAuthenticated]

    def put(self, request):
        course_section = request.data.get('course_section', '')
        post_id = request.data.get('post_id', '')
        
        if course_section=='' or post_id=='':
            return Response(status=status.HTTP_400_BAD_REQUEST)

        try:
            post = DiscussionPost.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':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=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
            publish_msg = 'Post Published Successfully'
        else:
            post.is_published = False
            publish_msg = 'Post Unpublished Successfully'
        post.save()
        
        return Response({"message": publish_msg},status=status.HTTP_200_OK)


class DiscussionReplyList(APIView):
    permission_classes = [IsAuthenticated]

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

        try:
            post = DiscussionPost.objects.get(id=post_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
        course_section = post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=user_information.user.id)).exists()

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

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

        replies = DiscussionReply.objects.filter(
                                                    Q(discussion_post__id=post_id) & 
                                                    Q(parent_reply=None)).order_by('created_at')
        
        serializer = DiscussionReplySerializer(replies, many=True, context={'request_user': request.user})
        
        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request):
        post_id = request.data.get('post_id', '')
        parent_reply_id = request.data.get('parent_reply_id', '')#this is post owner id
        content = request.data.get('reply_data', '')
        attachment = request.FILES.getlist('attachment')
        parent_reply = None
        # print('dsd')
        
        try:
            post = DiscussionPost.objects.get(id=post_id)
            if parent_reply_id != '':
                parent_reply = DiscussionReply.objects.get(id=parent_reply_id)
        except:
            return Response({'post not found'},status=status.HTTP_404_NOT_FOUND)    

        try:
            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
        course_section = post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=user_information.user.id)).exists()

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

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

        reply = DiscussionReply.objects.create(
                                                user=request.user, 
                                                discussion_post=post, 
                                                parent_reply=parent_reply, 
                                                content=content,
                                                is_deleted=False)

        for a in attachment:
            DiscussionReplyAttachment.objects.create(discussion_reply=reply, attachment=a)

        return Response({"message": "Reply Seccess"},status=status.HTTP_201_CREATED)    


class DiscussionReplyDetails(APIView):
    permission_classes = [IsAuthenticated]

    def put(self, request):
        reply_id = request.data.get('reply_id', '')
        reply_data = request.data.get('reply_data', '')
        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:
            reply = DiscussionReply.objects.get(id=reply_id)
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        
        try:
            user_information = UserInformation.objects.get(Q(user=request.user))
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # Check if user has access to the course
        course_section = reply.discussion_post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=user_information.user.id)).exists()

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

        if reply.is_deleted == True:
            return Response(status=status.HTTP_400_BAD_REQUEST)
        if request.user != reply.user:
            return Response(status=status.HTTP_401_UNAUTHORIZED)
        
        old_attachments_in_database = reply.attachments.all()
        
        for a in old_attachments_in_database:
            if a.attachment not in old_attachments:
                a.delete()

        for a in new_attachments:
            DiscussionReplyAttachment.objects.create(discussion_reply=reply, attachment=a)
        
        reply.content = reply_data
        reply.is_edited = True
        reply.save()

        return Response({"message":"Updated"},status=status.HTTP_200_OK)

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

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

        try:
            reply = DiscussionReply.objects.get(id=reply_id)
        except:
            return Response(status=status.HTTP_404_NOT_FOUND)
        
        try:
            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
        course_section = reply.discussion_post.usercourse.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(instructor=instructor_id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        elif user_information.role == 'Student':
            course_access = UserCourse.objects.filter(
                                                    Q(id=course_section) &
                                                    Q(user=user_information.user.id)).exists()

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

        if user_information.role != 'Admin' and user_information.role!='Instructor' and reply.user != request.user:
            return Response(status=status.HTTP_401_UNAUTHORIZED)
        
        reply_attachments = DiscussionReplyAttachment.objects.filter(Q(discussion_reply=reply))

        for a in reply_attachments:
            a.delete()

        reply.content = "This reply has been deleted"
        reply.is_deleted = True
        reply.save()

        return Response({"message":"This reply has been deleted"},status=status.HTTP_200_OK)


class DiscussionAttachmentDownload(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        post_id = request.GET.get('post_id', '')
        file_path = request.GET.get('file_path', '')
        attachment_source = request.GET.get('attachment_source', '')
        
        try:
            post = DiscussionPost.objects.get(Q(id=post_id))
            user_information = UserInformation.objects.get(Q(user=request.user))
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # Check if user has access to the course
        course_id = post.course.id
        if user_information.role == 'Instructor':
            instructor_id = Instructor.objects.get(user=request.user)
            course_access = Course.objects.filter(
                                                    Q(id=course_id) &
                                                    Q(instructor__user__id=instructor_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__user__id=user_information.user.id)).exists()
            
            if course_access is False:
                return Response(status=status.HTTP_401_UNAUTHORIZED)

        if file_path == '':
            return Response(status=status.HTTP_400_BAD_REQUEST)
        
        try:
            file_path = file_path.split('/media/', 1)[1]           # remove everything before and including '/media/' substring
        except:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        # 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.  
        file_path = os.path.dirname(file_path).replace('%20', ' ') + '/' + os.path.basename(file_path) 
        full_path = os.path.join(settings.MEDIA_ROOT, file_path)
        file_exists = False
        
        if attachment_source == 'post':
            file_exists = DiscussionPostAttachment.objects.filter(Q(attachment=file_path)).exists()
        elif attachment_source == 'reply':
            file_exists = DiscussionReplyAttachment.objects.filter(Q(attachment=file_path)).exists()
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if file_exists is False:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        with open(full_path, 'rb') as f:
            response = HttpResponse(
                f.read(), 
                headers={
                    'Content-Type': 'application/octet-stream',
                    'Content-Disposition': 'attachment; filename="'+os.path.basename(full_path)+'"'
                },
            )

            return response


class DiscussionUpvoteView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        post_id = request.data.get('post_id', '')
        reply_id = request.data.get('reply_id', '')
        
        if post_id != '' and reply_id == '':
            try:
                post = DiscussionPost.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_section = post.usercourse.id
            if user_information.role == 'Instructor':
                instructor_id = Instructor.objects.get(user=request.user)
                course_access = UserCourse.objects.filter(
                                                        Q(id=course_section) &
                                                        Q(instructor=instructor_id)).exists()
                
                if course_access is False:
                    return Response(status=status.HTTP_401_UNAUTHORIZED)
            elif user_information.role == 'Student':
                course_access = UserCourse.objects.filter(
                                                        Q(id=course_section) &
                                                        Q(user=user_information.user.id)).exists()

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

                post_upvote = DiscussionUpvote.objects.filter(Q(user=request.user) & Q(discussion_post=post))
                
                if post_upvote.exists():
                    post_upvote.delete()
                else:
                    DiscussionUpvote.objects.create(user=request.user, discussion_post=post)
        elif post_id == '' and reply_id != '':
            try:
                reply = DiscussionReply.objects.get(id=reply_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_section = reply.discussion_post.usercourse.id
            if user_information.role == 'Instructor':
                instructor_id = Instructor.objects.get(user=request.user)
                course_access = UserCourse.objects.filter(
                                                        Q(id=course_section) &
                                                        Q(instructor=instructor_id)).exists()
                
                if course_access is False:
                    return Response(status=status.HTTP_401_UNAUTHORIZED)
            elif user_information.role == 'Student':
                course_access = UserCourse.objects.filter(
                                                        Q(id=course_section) &
                                                        Q(user=user_information.user.id)).exists()
                if course_access is False:
                    return Response(status=status.HTTP_401_UNAUTHORIZED)

            if reply.is_deleted == True:
                return Response(status=status.HTTP_400_BAD_REQUEST)

            reply_upvote = DiscussionUpvote.objects.filter(Q(user=request.user) & Q(discussion_reply=reply))

            if reply_upvote.exists():
                reply_upvote.delete()
            else:
                DiscussionUpvote.objects.create(user=request.user, discussion_reply=reply)
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        return Response({"message": "Liked"},status=status.HTTP_200_OK)
        