import json
from django.db.models.query_utils import Q
from rest_framework import response
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from core.models import Instructor, UserApproval, UserInformation, UserCourse, Course, HoldWeek, UserLoginSession, Exam, ExamFeedback, AcademicSession, CoursePayment, CourseMember
from django.contrib.auth.models import User
from django.shortcuts import render
from django.core.mail import send_mail
from django.contrib.auth.models import User
from django.db.models import Q, Value
from django.db.models.functions import Concat
from .serializers import UserCourseSerializer, HoldWeekSerializer, InstructorExamFeedbackSerializer, ExamFeedbackSerializer, CourseInvitationSerializer


# Create your views here.
class StudentList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = self.request.user
        error = 'No Error'
        try:
            user_information = UserInformation.objects.get(user=user.id)
        except UserInformation.DoesNotExist:
            error = 'Cannot find admin user'
            return Response({'error': error}, status=status.HTTP_404_NOT_FOUND)

        search = request.GET.get('search', '')
        offset = int(request.GET.get('offset', 0))
        limit = int(request.GET.get('limit', 0))
        count = 0
        
        data = []
        user_data = {}
        if user_information:
            if user_information.role == 'Admin':
                count = User.objects.filter(Q(userinformation__role='Student')).annotate(full_name=Concat('first_name', Value(' '), 'last_name')).filter(
                        Q(full_name__trigram_word_similar=search) |
                        Q(full_name__icontains=search) |
                        Q(email__icontains=search)).count()

                all_students = User.objects.filter(Q(userinformation__role='Student')).annotate(full_name=Concat('first_name', Value(' '), 'last_name')).filter(
                        Q(full_name__trigram_word_similar=search) |
                        Q(full_name__icontains=search) |
                        Q(email__icontains=search)).order_by('-date_joined')[offset:limit]

                for student in all_students:
                    student_user_id = student.id
                    student_user_information = UserInformation.objects.get(
                        user=student_user_id)

                    data.append({
                        'id': student_user_id,
                        'username': student.username,
                        'fullname': f'{student.first_name} {student.last_name}',
                        'email': student.email,
                        'location': student_user_information.location,
                        'contact_number': str(student_user_information.phone_number),
                        'date_joined': student.date_joined
                    })

                user_data = {'user_data': data, 'total_users': count}
                response_status = status.HTTP_200_OK

                return Response(user_data, status=response_status)
            else:
                error = 'Unauthorized Access.'
                response_status = status.HTTP_401_UNAUTHORIZED
        else:
            error = 'Cannot find admin user.'
            response_status = status.HTTP_404_NOT_FOUND

        return Response({'error': error}, status=response_status)

    def delete(self, request):
        error = 'No Error'
        user = self.request.user
        counter = 0
        try:
            user_information = UserInformation.objects.get(user=user.id)
        except UserInformation.DoesNotExist:
            error = 'Cannot find admin user.'
            return Response({'error': error}, status=status.HTTP_404_NOT_FOUND)

        student_ids = request.data['selected_students']
        
        if user_information:
            if user_information.role == 'Admin':
                if student_ids:
                    for id in student_ids:
                        try:
                            user_student = User.objects.get(id=id)
                        except User.DoesNotExist:
                            error = 'Student does not exist.'
                            continue
                        user_student.delete()
                        counter = counter + 1

                    response_status = status.HTTP_200_OK
                    student_multiple = 'Student'
                    if counter > 1:
                        student_multiple = 'Students'
                    return Response({'success': f'{counter} {student_multiple} deleted.', 'error': error})
                else:
                    error = 'Bad request.'
                    response_status = status.HTTP_400_BAD_REQUEST
            else:
                error = 'Unauthorized access.'
                response_status = status.HTTP_401_UNAUTHORIZED
        else:
            error = 'Cannot find admin user.'
            response_status = status.HTTP_404_NOT_FOUND
        return Response({'error': error}, status=response_status)


class UserLoginSessionList(APIView):
    permission_classes = [IsAuthenticated]

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

        data = []
        if not user.is_anonymous:
            if UserLoginSession.objects.filter(user=student_id).exists():
                login_sessions = UserLoginSession.objects.filter(
                    user=student_id)
                device = 1
                for login_session in login_sessions:
                    data.append({
                        'id': login_session.id,
                        'device_count': device,
                        'address': login_session.address,
                        'login_time': login_session.login_time.strftime("%d %B, %Y %H:%M") if login_session.login_time else "",
                        'logout_time': login_session.logout_time.strftime("%d %B, %Y %H:%M") if login_session.logout_time else "",
                        'status': login_session.is_logged_in
                    })
                    device += 1

                response_status = status.HTTP_200_OK
            else:
                response_status = status.HTTP_404_NOT_FOUND
        else:
            response_status = status.HTTP_401_UNAUTHORIZED

        return Response(data, status=response_status)

    def put(self, request):
        user = self.request.user
        student_id = request.data['student_id']
        login_session_id = request.data['session_id']

        if not user.is_anonymous:
            session = UserLoginSession.objects.get(user=student_id, id=login_session_id)
            if session:
                session.is_logged_in = False

                session.save()

                data = []
                login_sessions = UserLoginSession.objects.filter(
                    user=student_id)
                device = 1
                for login_session in login_sessions:
                    data.append({
                        'id': login_session.id,
                        'device_count': device,
                        'address': login_session.address,
                        'login_time': login_session.login_time.strftime("%d %B, %Y %H:%M") if login_session.login_time else "",
                        'logout_time': login_session.logout_time.strftime("%d %B, %Y %H:%M") if login_session.logout_time else "",
                        'status': login_session.is_logged_in
                    })
                    device += 1

                response_status = status.HTTP_200_OK
            else:
                response_status = status.HTTP_404_NOT_FOUND
        else:
            response_status = status.HTTP_401_UNAUTHORIZED

        return Response(data, status=response_status)


class CourseEnroll(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = self.request.user
        course_id = request.GET.get('course_id', None)
        if not user.is_anonymous:
            try:
                user_course = UserCourse.objects.get(
                    user=user.id, course=course_id)
                if user_course:
                    if user_course.approval_status == 'Approved':
                        data = {
                            'course_status': 'Enrolled'
                        }
                    elif user_course.approval_status == 'Pending':
                        data = {
                            'course_status': 'Waiting for approval'
                        }
                    else:
                        data = {
                            'course_status': 'Enroll'
                        }
                    response_status = status.HTTP_200_OK
                else:
                    data = {
                        'course_status': 'Enroll'
                    }
                    response_status = status.HTTP_200_OK
            except UserCourse.DoesNotExist:
                raise ValidationError({'course_status': 'Not enrolled'})
        else:
            data = {
                'course_status': 'Enroll'
            }
            response_status = status.HTTP_401_UNAUTHORIZED

        return Response(data, status=response_status)

    def post(self, request):
        user = self.request.user
        course_id = request.data.get('course_id', None)
       
        if not user.is_anonymous:
            if request.user.userinformation.role == 'Student':
                if not UserCourse.objects.filter(user=user.id, course=course_id).exists():
                    if  CoursePayment.objects.filter(user=user.id, course=course_id).exists():
                        course = Course.objects.get(id=course_id)
                        
                        try:
                            user_courses = UserCourse.objects.create(
                                course=course,
                                is_paid=True,
                                name= user.userinformation.full_name
                            )
                            # user.user_course.add(user_courses)
                            user_courses.user.add(user)
                            response_status = status.HTTP_201_CREATED
                            responsr_data = 'Course enrolled successfuly'
                            # try:
                            #     course_section = user.user_course.add(user_courses)
                            #     response_status = status.HTTP_201_CREATED
                            #     responsr_data = 'Course enrolled and assigned to section successfuly'

                            # except Exception as e:
                            #     responsr_data = f'Error enrolling section: {str(e)}'
                            #     response_status = status.HTTP_500_INTERNAL_SERVER_ERROR 
                        except Exception as e:
                                responsr_data = f'Error enrolling course: {str(e)}'
                                response_status = status.HTTP_500_INTERNAL_SERVER_ERROR 
                    else:
                        response_status = status.HTTP_400_BAD_REQUEST
                        responsr_data = 'No Payment Data Found'    
                else:
                    response_status = status.HTTP_400_BAD_REQUEST
                    responsr_data = 'You Already Enrolled the course'
            else:
                response_status = status.HTTP_401_UNAUTHORIZED
                responsr_data = 'User not authenticated'
        else:
            response_status = status.HTTP_403_UNAUTHORIZED
            responsr_data = 'Please Login'

        return Response(responsr_data, status=response_status)


class CourseEnrollMultiuser(APIView):
    permission_classes = [IsAuthenticated]

    # def get(self, request):
    #     user = self.request.user
    #     course_id = request.GET.get('course_id', None)
    #     if not user.is_anonymous:
    #         try:
    #             user_course = UserCourse.objects.get(
    #                 user=user.id, course=course_id)
    #             if user_course:
    #                 if user_course.approval_status == 'Approved':
    #                     data = {
    #                         'course_status': 'Enrolled'
    #                     }
    #                 elif user_course.approval_status == 'Pending':
    #                     data = {
    #                         'course_status': 'Waiting for approval'
    #                     }
    #                 else:
    #                     data = {
    #                         'course_status': 'Enroll'
    #                     }
    #                 response_status = status.HTTP_200_OK
    #             else:
    #                 data = {
    #                     'course_status': 'Enroll'
    #                 }
    #                 response_status = status.HTTP_200_OK
    #         except UserCourse.DoesNotExist:
    #             raise ValidationError({'course_status': 'Not enrolled'})
    #     else:
    #         data = {
    #             'course_status': 'Enroll'
    #         }
    #         response_status = status.HTTP_401_UNAUTHORIZED

    #     return Response(data, status=response_status)

    def post(self, request):
        user = self.request.user
        request_by = request.data.get('request_by', None)
        course_id = request.data.get('course_id', None)
        section_id = request.data.get('section_id', None)
        responsr_data = ''
        subscription_count = CoursePayment.objects.get(user=request_by, course=course_id)
        section = section_id
        usercourse = UserCourse.objects.get(id=section) 
       
        requested_user = User.objects.get(id=request_by)
        users = usercourse.user.all()
        remaining_subscription = subscription_count.no_of_subscriptions - users.count()
        if not user.is_anonymous:
            if user.userinformation.role == 'Student':
                if requested_user.userinformation.role == 'Student':
                    if user:
                        if not UserCourse.objects.filter(user=user.id, course=course_id).exists():
                            if  CoursePayment.objects.filter(user=request_by, course=course_id).exists():
                                if remaining_subscription != 0:
                                    course_users = section
                                    if UserCourse.objects.filter(id=section).exists():
                                        try:
                                            user.user_course.add(course_users)
                                            response_status = status.HTTP_201_CREATED
                                            responsr_data = 'Invitaion Accepted. You Will Be Enroll To Following Section Soon'
                                            course_member = CourseMember.objects.get(invite_to=user.email, course=course_id)
                                            course_member.is_accept = True
                                            course_member.save(update_fields=['is_accept'])
                                        except Exception as e:
                                            responsr_data = f'Error enrolling course: {str(e)}'
                                            response_status = status.HTTP_500_INTERNAL_SERVER_ERROR 
                                    else:
                                        response_status = status.HTTP_400_BAD_REQUEST
                                        responsr_data = 'No Section Found'
                                else:
                                    response_status = status.HTTP_400_BAD_REQUEST
                                    responsr_data = f'Remaining subscription: {remaining_subscription}'
                            else:
                                response_status = status.HTTP_400_BAD_REQUEST
                                responsr_data = 'No Payment Data Found'    
                        else:
                            response_status = status.HTTP_400_BAD_REQUEST
                            responsr_data = f'You Already Enrolled the course With this section. Remaining subscription: {remaining_subscription}'
                    else:
                        response_status = status.HTTP_400_BAD_REQUEST
                        responsr_data = 'Your Chosen Student Not Registered Yet'
                else:
                    response_status = status.HTTP_400_BAD_REQUEST
                    responsr_data = 'Your Are Not Registered'
            else:
                response_status = status.HTTP_401_UNAUTHORIZED
                responsr_data = 'User not authenticated'
        else:
            response_status = status.HTTP_403_UNAUTHORIZED
            responsr_data = 'Please Login'

        return Response({"message": responsr_data}, status=response_status)



class StudentCourseHoldAccess(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        data = json.loads(request.body)
        id = data['id']
        hold_access = data['hold_access']

        if not request.user.is_anonymous:
            if request.user.userinformation.role == 'Admin' or request.user.userinformation.role == 'AdminInstructor':
                usercourse = UserCourse.objects.get(id=id)
                usercourse.hold_access = hold_access
                usercourse.save()

                return Response({'hold_access': hold_access}, status=status.HTTP_202_ACCEPTED)
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)


class StudentCourseWeekAccessibility(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, **kwargs):
        id = kwargs['id']

        if not request.user.is_anonymous:
            if request.user.userinformation.role == 'Admin' or request.user.userinformation.role == 'AdminInstructor':
                user = User.objects.get(id=id)
                studentname = f"{user.first_name} {user.last_name}"

                usercourses = UserCourse.objects.filter(user=user)
                serializer = UserCourseSerializer(usercourses, many=True)

                return Response({'studentname': studentname, 'courses': serializer.data})
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)


class StudentCourseHoldWeek(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        data = json.loads(request.body)
        id = data['id']
        week = data['week']

        if not request.user.is_anonymous:
            if request.user.userinformation.role == 'Admin' or request.user.userinformation.role == 'AdminInstructor':
                usercourse = UserCourse.objects.get(id=id)
                if not HoldWeek.objects.filter(usercourse=usercourse, week=week).exists():
                    holdweek = HoldWeek.objects.create(
                        usercourse=usercourse,
                        week=week,
                    )
                    serializer = HoldWeekSerializer(holdweek)

                    return Response(serializer.data, status=status.HTTP_201_CREATED)
                else:
                    return Response(status=status.HTTP_409_CONFLICT)
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)

    def delete(self, request):
        data = json.loads(request.body)
        id = data['id']

        if not request.user.is_anonymous:
            if request.user.userinformation.role == 'Admin' or request.user.userinformation.role == 'AdminInstructor':
                if HoldWeek.objects.filter(id=id).exists():
                    holdweek = HoldWeek.objects.get(id=id)
                    holdweek.delete()

                    return Response(status=status.HTTP_202_ACCEPTED)
                else:
                    return Response(status=status.HTTP_404_NOT_FOUND)
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)


class ExamFeedbackList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, **kwargs):
        id = kwargs['id']

        try:
            course = Course.objects.get(id=id)
        except Course.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        if not request.user.is_anonymous:
            if request.user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
                students = course.student.all()
                serializer = InstructorExamFeedbackSerializer(
                    students, many=True, context={'course_id': id})

                return Response(serializer.data, status=status.HTTP_200_OK)
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)


class ExamFeedbackDetails(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        course_id = request.data['course_id']
        student_id = request.data['student_id']
        examfeedback = request.data['examfeedback']
        title = request.data['title']

        if not request.user.is_anonymous:
            if request.user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
                examfeedback = ExamFeedback.objects.create(
                    course_id=course_id,
                    student_id=student_id,
                    file=examfeedback,
                    title=title,
                )
                serializer = ExamFeedbackSerializer(examfeedback)

                return Response(serializer.data, status=status.HTTP_201_CREATED)
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)

    def delete(self, request):
        data = json.loads(request.body)
        id = data['id']

        if not request.user.is_anonymous:
            if request.user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
                if ExamFeedback.objects.filter(id=id).exists():
                    examfeedback = ExamFeedback.objects.get(id=id)
                    examfeedback.delete()

                    return Response(status=status.HTTP_202_ACCEPTED)
                else:
                    return Response(status=status.HTTP_404_NOT_FOUND)
            else:
                return Response(status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_404_NOT_FOUND)


class FilteredStudents(APIView):
    permission_classes = [IsAuthenticated]

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

        user = self.request.user
        user_information = UserInformation.objects.get(user=user.id)

        data = []
        if user_information:
            if user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
                approved_students = UserApproval.objects.filter(Q(approval_status='Approved', user__userinformation__role='Student') &
                                                                (Q(user__first_name__icontains=search_key) |
                                                                Q(user__last_name__icontains=search_key) |
                                                                Q(user__email__icontains=search_key) |
                                                                Q(user__userinformation__phone_number__icontains=search_key) |
                                                                Q(user__usercourse__course__academic_session__title__icontains=search_key) |
                                                                Q(user__userinformation__location__icontains=search_key)))
                for student in approved_students:
                    student_user_id = student.user.id
                    student_user_information = UserInformation.objects.get(
                        user=student_user_id)
                    courses = Course.objects.filter(student=student_user_id)
                    course_name = []
                    for course in courses:
                        course_name.append(course.title)

                    academic_session = AcademicSession.objects.filter(
                        course__in=courses).distinct().values_list('title', flat=True)

                    session = []
                    login_sessions = UserLoginSession.objects.filter(
                        user=student_user_id)
                    device = 1
                    for login_session in login_sessions:
                        session.append({
                            'device_count': device,
                            'address': login_session.address,
                            'login_time': login_session.login_time.strftime("%d %B, %Y %H:%M") if login_session.login_time else "",
                            'logout_time': login_session.logout_time.strftime("%d %B, %Y %H:%M") if login_session.logout_time else "",
                            'status': login_session.is_logged_in
                        })
                        device += 1

                    data.append({
                        'id': student_user_id,
                        'name': f'{student.user.first_name} {student.user.last_name}',
                        'email': student.user.email,
                        'location': student_user_information.location,
                        'contact_number': str(student_user_information.phone_number),
                        'course_name': course_name,
                        'academic_session': academic_session,
                        'session': session,
                    })
                response_status = status.HTTP_200_OK
            else:
                response_status = status.HTTP_401_UNAUTHORIZED
        else:
            response_status = status.HTTP_404_NOT_FOUND

        return Response(data, status=response_status)


class SessionStudentsList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = self.request.user
        session_id = request.GET.get('session_id', None)
        exam_id = request.GET.get('exam_id', None)

        if not user.is_anonymous:
            if user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
                if Exam.objects.filter(id=exam_id).exists():
                    exam = Exam.objects.get(id=exam_id)
                    if Course.objects.filter(id=exam.course.id, academic_session=session_id).exists():
                        students = Course.objects.filter(id=exam.course.id, academic_session=session_id).values_list('student', flat=True)
                        data = []
                        for student in students:
                            if User.objects.filter(id=student, userapproval__approval_status='Approved').exists():
                                user = User.objects.get(id=student, userapproval__approval_status='Approved')
                                data.append({
                                    'id': user.id,
                                    'name': user.first_name + " " + user.last_name
                                })
                        return Response(data, status=status.HTTP_200_OK)
                    else:
                        return Response(status=status.HTTP_404_NOT_FOUND)
                else:
                    return Response(status=status.HTTP_404_NOT_FOUND)
            else:
                return Response(status=status.HTTP_403_FORBIDDEN)
        else:
            return Response(status=status.HTTP_401_UNAUTHORIZED)


class CourseActivityList(APIView):
    permission_classes = [IsAuthenticated]

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

        if not user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        return Response()


class CourseInvitation(APIView):
    permission_classes= [IsAuthenticated]

    def get(self, request):

        user = request.user
        if CourseMember.objects.filter(invite_to=user.email).exists():
                try:
                    invite_list = CourseMember.objects.get(invite_to=user.email) 
                    
                    serializer = CourseInvitationSerializer(invite_list)

                    return Response(serializer.data, status=status.HTTP_200_OK)
              
                except Course.DoesNotExist:
                    return Response({'error': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
                except UserCourse.DoesNotExist:
                    return Response({'error': 'Section not found'}, status=status.HTTP_404_NOT_FOUND)
        else:
            return Response({'error': 'No Invitation Found'}, status=status.HTTP_404_NOT_FOUND)


    
    def post(self, request):
        
        user = request.user
        course_id = request.POST.get('course_id')
        section_id = request.POST.get('section_id')
        invite_to = request.POST.get('invite_to')

        if UserCourse.objects.filter(user=request.user, id=section_id, approval_status='Approved').exists():
            if Course.objects.filter(id=course_id).exists():
                if User.objects.filter(email=invite_to).exists():
                    if not CourseMember.objects.filter(invite_to=invite_to).exists():
                        try:
                            course = Course.objects.get(id=course_id)  # Use get() for a single instance
                            section = UserCourse.objects.get(id=section_id)  # Use get() for a single instance

                            CourseMember.objects.create(
                                user=user,
                                invite_to=invite_to,
                                is_accept=False,
                                course=course,  # Pass the single instance
                                usercourse=section,  # Pass the single instance
                            )

                            return Response({'message': f'Sending Invitation to {invite_to}'}, status=status.HTTP_201_CREATED)

                        except Course.DoesNotExist:
                            return Response({'error': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
                        except UserCourse.DoesNotExist:
                            return Response({'error': 'Section not found'}, status=status.HTTP_404_NOT_FOUND)
                    else:
                        return Response({'error': 'This email already Exists'}, status=status.HTTP_401_UNAUTHORIZED)
                else:
                    return Response({'error': 'Your Invited Person Not Registered'}, status=status.HTTP_404_NOT_FOUND)
            else:
                return Response({'error': 'Your are not enrolled into This Course'}, status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response(status=status.HTTP_401_UNAUTHORIZED)


class CourseInvitationDetails(APIView):
    permission_classes= [IsAuthenticated]

    

    def get(self, request):

        section_id = request.GET.get('section_id')

        user = request.user
        if CourseMember.objects.filter(user=user).exists():
                try:
                    invite_list = CourseMember.objects.filter(usercourse=section_id) 
                    
                    serializer = CourseInvitationSerializer(invite_list, many=True)

                    return Response(serializer.data, status=status.HTTP_200_OK)               

                except Course.DoesNotExist:
                    return Response({'error': 'Course not found'}, status=status.HTTP_404_NOT_FOUND)
                except UserCourse.DoesNotExist:
                    return Response({'error': 'Section not found'}, status=status.HTTP_404_NOT_FOUND)
        else:
            return Response({'error': 'No Invitation Found'}, status=status.HTTP_401_UNAUTHORIZED)


    