import json
from django.db.models.query_utils import Q
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import ValidationError
from django.utils import timezone

from core.models import User, OnlineMeeting, UserCourse, Instructor, InstructorMeetingJoin, StudentMeetingJoin
from .serializers import OnlineMeetingSerializer, OnlineMeetingInstructorSerializer
from django.db.models import Count, Prefetch


class InstructorAllMeetingView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            instructor = Instructor.objects.get(user=request.user)
        except Instructor.DoesNotExist:
            return Response({"error": "Instructor not found"}, status=status.HTTP_404_NOT_FOUND)

        # Check if the user is an instructor
        if request.user.userinformation.role != 'Instructor':
            return Response({"error": "Unauthorized"}, status=status.HTTP_401_UNAUTHORIZED)

        # Retrieve approved UserCourse instances assigned to this instructor
        user_courses = UserCourse.objects.filter(approval_status='Approved', instructor=instructor)

        # Retrieve OnlineMeeting instances related to those UserCourses
        meetings = OnlineMeeting.objects.filter(usercourse__in=user_courses, start_time__gte=timezone.now()).order_by('start_time')  # Adjust based on relationships

        # Serialize the OnlineMeeting instances
        serializer = OnlineMeetingInstructorSerializer(meetings, many=True)

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

class OnlineMeetingList(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        usercourse_id = request.GET.get('usercourse_id', None)
        if request.user.userinformation.role == 'Student':
            online_meetings = OnlineMeeting.objects.filter(usercourse_id=usercourse_id, is_active=True)
        else:
            online_meetings = OnlineMeeting.objects.filter(usercourse_id=usercourse_id)

        serializer = OnlineMeetingSerializer(online_meetings, many=True)

        return Response(serializer.data)

    def post(self, request):
        data = request.data

        # Check if the user's role is allowed
        if not request.user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
            return Response({'error': 'Unauthorized access'}, status=status.HTTP_401_UNAUTHORIZED)

        # Validate required fields
        required_fields = ['usercourse_id', 'client', 'topic', 'meeting_url', 'start_time', 'is_active']
        for field in required_fields:
            if field not in data:
                return Response({'error': f'Missing required field: {field}'}, status=status.HTTP_400_BAD_REQUEST)

        user_course = UserCourse.objects.filter(id=data['usercourse_id']).select_related('course').first()
        created_classes = OnlineMeeting.objects.filter(usercourse=data['usercourse_id']).count()

        if user_course:
            number_classes = user_course.course.number_class
        else:
            number_classes = None  # Handle the case when no UserCourse is found

        # Check if created_classes has reached or exceeded the number_classes limit
        if created_classes >= number_classes:
            return Response({'error': 'You cannot create more classes. The limit has been reached.'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            # Only attempt to create the OnlineMeeting if the limit has not been reached
            if created_classes < number_classes:
                online_meeting = OnlineMeeting.objects.create(
                    usercourse_id=data['usercourse_id'],
                    client=data['client'],
                    topic=data['topic'],
                    meeting_url=data.get('meeting_url'),  # Use .get() to handle optional fields
                    meeting_id=data.get('meeting_id', None),
                    passcode=data.get('passcode', None),
                    start_time=data['start_time'],
                    duration=data.get('duration', None),
                    details=data.get('details', None),  # Optional
                    is_active=data['is_active'] if isinstance(data['is_active'], bool) else (data['is_active'] == 'True')
                )

                # Serialize the created object
                serializer = OnlineMeetingSerializer(online_meeting)

                # Return success response
                return Response({'message': 'Live Class Created Successfully'}, status=status.HTTP_201_CREATED)

        except ValidationError as e:
            return Response({'error': f'Validation Error: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            return Response({'error': f'An error occurred: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class OnlineMeetingListAdmin(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        offset = int(request.GET.get('offset', 0))
        limit = int(request.GET.get('limit', 10))

        if user.userinformation.role == 'Admin':
            online_meetings_count = OnlineMeeting.objects.all().count()
            online_meetings = OnlineMeeting.objects.all().order_by('-start_time')[offset:limit]
        else:
            return Response({'error': 'Unauthorized access.'}, status=status.HTTP_400_BAD_REQUEST)

        serializer = OnlineMeetingInstructorSerializer(online_meetings, many=True)

        return Response({'online_meeting_data': serializer.data, 'online_meeting_count': online_meetings_count}, status=status.HTTP_200_OK)


class OnlineMeetingDetails(APIView):
    permission_classes = [IsAuthenticated]

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

        try:
            online_meeting = OnlineMeeting.objects.get(id=id)
        except OnlineMeeting.DoesNotExist:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        serializer = OnlineMeetingSerializer(online_meeting)

        return Response(serializer.data)

    def put(self, request):
        data = request.data

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

        try:
            online_meeting = OnlineMeeting.objects.get(id=data['id'])
        except OnlineMeeting.DoesNotExist:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        fields_to_update = [
            'client',
            'topic',
            'meeting_url',
            'meeting_id',
            'passcode',
            'start_time',
            'duration',
            'details',
        ]

        for field in fields_to_update:
            if field in data and data[field] is not None:
                setattr(online_meeting, field, data[field])

        online_meeting.save()
        
        serializer = OnlineMeetingSerializer(online_meeting)

        return Response({'message': 'Live Class Update Succefully'}, status=status.HTTP_200_OK)

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

        # Check if the user has the appropriate role
        if request.user.userinformation.role not in ['Admin', 'AdminInstructor', 'Instructor']:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        try:
            # Try to get and delete the online meeting
            online_meeting = OnlineMeeting.objects.get(id=id)
            online_meeting.delete()
        except OnlineMeeting.DoesNotExist:
            return Response({'error': 'Online meeting not found'}, status=status.HTTP_400_BAD_REQUEST)

        # Return success message as a dictionary
        return Response({'success': 'Deleted'}, status=status.HTTP_202_ACCEPTED)


class Publish(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        online_meeting_id = request.data.get('online_meeting_id', None)
        is_active = request.data.get('is_active', True)

        if is_active == True:
            activ_status = "Meeeting Published"
        else:
            activ_status = "Meeeting Unpublished"
        if not request.user.userinformation.role in ['Admin', 'AdminInstructor', 'Instructor']:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        try:
            online_meeting = OnlineMeeting.objects.get(id=online_meeting_id)
        except OnlineMeeting.DoesNotExist:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        online_meeting.is_active = is_active
        online_meeting.save()

        return Response({'success':activ_status},status=status.HTTP_200_OK)

class InstructorJoinMeetingView(APIView):
    def post(self, request):
        data = request.data
        
        # Ensure user has a userinformation and role
        if not hasattr(request.user, 'userinformation') or not request.user.userinformation:
            return Response({'error': 'User information not found'}, status=status.HTTP_400_BAD_REQUEST)
        
        # Check if the user's role is allowed
        if request.user.userinformation.role not in ['Admin', 'AdminInstructor', 'Instructor']:
            return Response({'error': 'Unauthorized access'}, status=status.HTTP_401_UNAUTHORIZED)
        
        try:
            instructor = Instructor.objects.get(user=request.user)
        except Instructor.DoesNotExist:
            return Response({'error': 'Instructor not found for this user'}, status=status.HTTP_404_NOT_FOUND)

        # Retrieve the OnlineMeeting instance by its ID
        try:
            online_meeting = OnlineMeeting.objects.get(id=data['live_class'])
        except OnlineMeeting.DoesNotExist:
            return Response({'error': 'Online meeting not found'}, status=status.HTTP_404_NOT_FOUND)

        # Check if the instructor has already joined the live class
        if InstructorMeetingJoin.objects.filter(instructor=instructor, live_class=online_meeting).exists():
            return Response({'error': 'Instructor has already joined this live class'}, status=status.HTTP_400_BAD_REQUEST)

        joined_at = timezone.now()

        # Create InstructorMeetingJoin with the OnlineMeeting instance
        try:
            online_meeting_join_instructor = InstructorMeetingJoin.objects.create(
                live_class=online_meeting,  # Use the instance of OnlineMeeting here
                instructor=instructor,
                joined_at=joined_at,
            )
            return Response({'message': 'Successfully joined the live class'}, status=status.HTTP_201_CREATED)

        except Exception as e:
            return Response({'error': f'An error occurred: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


    def put(self, request):
        try:
            # Fetch the meeting join instance by pk
            liveclass_id = request.data.get('liveclassid')
            meeting_join_instance = InstructorMeetingJoin.objects.get(live_class=liveclass_id)
        except InstructorMeetingJoin.DoesNotExist:
            return Response({'error': 'Instructor meeting join not found'}, status=status.HTTP_404_NOT_FOUND)

        # Extract the summary from the request data
        summary = request.data.get('summary', None)

        if summary:
            # Only update the summary field
            meeting_join_instance.summary = summary
            meeting_join_instance.save()
            return Response({'message': 'Summary updated successfully'}, status=status.HTTP_200_OK)
        
        return Response({'error': 'No summary provided in the request'}, status=status.HTTP_400_BAD_REQUEST)


class StudentJoinMeetingView(APIView):
    def post(self, request):
        data = request.data
        
        # Ensure user has a userinformation and role
        if not hasattr(request.user, 'userinformation') or not request.user.userinformation:
            return Response({'error': 'User information not found'}, status=status.HTTP_400_BAD_REQUEST)
        
        # Check if the user's role is allowed
        if request.user.userinformation.role not in ['Admin', 'Student']:
            return Response({'error': 'Unauthorized access'}, status=status.HTTP_401_UNAUTHORIZED)
        
        live_class_id = data.get('live_class')
        if not live_class_id:
            return Response({'error': 'Missing required field: live_class'}, status=status.HTTP_400_BAD_REQUEST)

        # Retrieve the OnlineMeeting instance by its ID
        try:
            online_meeting = OnlineMeeting.objects.get(id=live_class_id)
        except OnlineMeeting.DoesNotExist:
            return Response({'error': 'Online meeting not found'}, status=status.HTTP_404_NOT_FOUND)

        # Check if the student has already joined the live class
        if StudentMeetingJoin.objects.filter(student=request.user, live_class=online_meeting).exists():
            return Response({'error': 'Student has already joined this live class'}, status=status.HTTP_400_BAD_REQUEST)

        joined_at = timezone.now()

        # Create StudentMeetingJoin with the OnlineMeeting instance
        try:
            online_meeting_join_student = StudentMeetingJoin.objects.create(
                live_class=online_meeting,  # Use the instance of OnlineMeeting here
                student=request.user,
                joined_at=joined_at,
            )
            return Response({'message': 'Successfully joined the live class'}, status=status.HTTP_201_CREATED)

        except Exception as e:
            return Response({'error': f'An error occurred: {str(e)}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class SessionReportView(APIView):
    def get(self, request):
        user_info = getattr(request.user, "userinformation", None)
        if not user_info:
            return Response({'error': 'User information not found'}, status=status.HTTP_400_BAD_REQUEST)

        role = user_info.role

        if role == 'Admin':
            offset = int(request.GET.get('offset', ''))
            limit = int(request.GET.get('limit', ''))
            # Fetch all meetings along with joined instructors & students

            session_report_count = OnlineMeeting.objects.prefetch_related(
                Prefetch('instructors', queryset=InstructorMeetingJoin.objects.select_related('instructor__user')),
                Prefetch('students', queryset=StudentMeetingJoin.objects.select_related('student'))
            ).annotate(
                instructor_count=Count('instructors'),
                student_count=Count('students')
            ).count()

            meetings = OnlineMeeting.objects.prefetch_related(
                Prefetch('instructors', queryset=InstructorMeetingJoin.objects.select_related('instructor__user')),
                Prefetch('students', queryset=StudentMeetingJoin.objects.select_related('student'))
            ).annotate(
                instructor_count=Count('instructors'),
                student_count=Count('students')
            )[offset:limit]
            
            # Serialize data manually
            session_data = [
                {
                    "id": meeting.id,
                    "topic": meeting.topic,
                    "start_time": meeting.start_time,
                    "duration": meeting.duration,
                    "is_active": meeting.is_active,
                    "instructors": [
                        {
                            "id": instructor.instructor.id if instructor.instructor else None,
                            "name": instructor.instructor.user.get_full_name() if instructor.instructor else "Unknown",
                            "joined_at": instructor.joined_at,
                            "summary": instructor.summary
                        }
                        for instructor in meeting.instructors.all()
                    ],
                    "students": [
                        {
                            "id": student.student.id,
                            "name": student.student.get_full_name(),
                            "joined_at": student.joined_at
                        }
                        for student in meeting.students.all()
                    ]
                }
                for meeting in meetings
            ]

            return Response({"session_reports": session_data, 'session_report_count': session_report_count})

        elif role in ['Instructor', 'Student']:
            course_section = request.GET.get('course_section')
            
            if not course_section:
                return Response({"session_reports": []})  # Return an empty report instead of 404

            # Fetch only the meetings this instructor joined
            meetings = OnlineMeeting.objects.filter(
                usercourse=course_section
            ).prefetch_related(
                Prefetch('instructors', queryset=InstructorMeetingJoin.objects.select_related('instructor__user')),
                Prefetch('students', queryset=StudentMeetingJoin.objects.select_related('student'))
            ).annotate(
                instructor_count=Count('instructors'),
                student_count=Count('students')
            )

            session_data = [
                {
                    "id": meeting.id,
                    "topic": meeting.topic,
                    "start_time": meeting.start_time,
                    "duration": meeting.duration,
                    "is_active": meeting.is_active,
                    "instructors": [
                        {
                            "id": instructor.instructor.id if instructor.instructor else None,
                            "name": instructor.instructor.user.get_full_name() if instructor.instructor else "Unknown",
                            "joined_at": instructor.joined_at,
                            "summary": instructor.summary
                        }
                        for instructor in meeting.instructors.all()
                    ],
                    "students": [
                        {
                            "id": student.student.id,
                            "name": student.student.get_full_name(),
                            "joined_at": student.joined_at
                        }
                        for student in meeting.students.all()
                    ]
                }
                for meeting in meetings
            ]

            return Response({"session_reports": session_data})

        else:
            return Response({'error': 'Unauthorized access'}, status=status.HTTP_401_UNAUTHORIZED)


class SessionReportDetails(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        user_information = user.userinformation
        # course_section = request.data.get('id', '')
        meeting_id = request.GET.get('id', '')

        if user_information.role == 'Admin':
            meetings = OnlineMeeting.objects.filter(
                id=meeting_id
            ).prefetch_related(
                Prefetch('instructors', queryset=InstructorMeetingJoin.objects.select_related('instructor__user')),
                Prefetch('students', queryset=StudentMeetingJoin.objects.select_related('student'))
            ).annotate(
                instructor_count=Count('instructors'),
                student_count=Count('students')
            )

            session_data = [
                {
                    "id": meeting.id,
                    "course": meeting.usercourse.course.title,
                    "topic": meeting.topic,
                    "start_time": meeting.start_time,
                    "duration": meeting.duration,
                    "is_active": meeting.is_active,
                    "instructors": [
                        {
                            "id": instructor.instructor.id if instructor.instructor else None,
                            "name": instructor.instructor.user.get_full_name() if instructor.instructor else "Unknown",
                            "joined_at": instructor.joined_at,
                            "summary": instructor.summary
                        }
                        for instructor in meeting.instructors.all()
                    ],
                    "students": [
                        {
                            "id": student.student.id,
                            "name": student.student.get_full_name(),
                            "joined_at": student.joined_at
                        }
                        for student in meeting.students.all()
                    ]
                }
                for meeting in meetings
            ]

            return Response({'session_reports': session_data}, status=status.HTTP_200_OK)
        else:
            return Response({'error': 'Unauthorized access.'}, status=status.HTTP_401_UNAUTHORIZED)