from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.db import transaction
from django.db import models
from .utils.ai import generate_questions_with_ai
from academics.models import AcademicClass, Subject
from chat.models import (
    ChatRoom,
    ChatParticipantTeacher,
    ChatParticipantStudent,
    Message,
    MessageDelivery,
    ChatParticipantParent,
    MessageReadReceipt
)
from chat.utils import broadcast_new_message
from activities.utils import log_teacher_activity
from .teacher_payslip_views import (
    TeacherMyPaySlipsView,
    TeacherPaySlipDetailView,
    TeacherPaySlipSummaryView,
    TeacherCurrentPayStructureView,
    TeacherAcknowledgePaySlipView,
    TeacherDownloadPaySlipView
)

from .teacher_study_material_views import (
    StudyMaterialListCreateView,
    StudyMaterialDetailView,
    StudyMaterialDownloadView,
    PreviousYearPaperListCreateView,
    PreviousYearPaperDetailView,
    PreviousYearPaperDownloadView,
    TeacherSubjectsForMaterialsView,
)

from .teacher_marks_views import (
    TeacherSubjectsStandardsView,
    TeacherClassExamsView,
    TeacherSubjectsWithClassesView,
    TeacherClassStudentsForMarksView,
    TeacherEnterStudentMarksView,
    TeacherBulkMarksEntryView,
    TeacherSubjectMarksSummaryView,
    TeacherSubmitMarksView,
    TeacherPendingMarksView,
    TeacherExamSubjectsForMarksView,
)

from .teacher_class_test_views import (
    TeacherAvailablePeriodsView,
    ClassTestListCreateView as TeacherClassTestListCreateView,
    ClassTestDetailView as TeacherClassTestDetailView,
    ClassTestStudentsView as TeacherClassTestStudentsView,
    ClassTestBulkMarksView as TeacherClassTestBulkMarksView,
    ClassTestSummaryView as TeacherClassTestSummaryView,
)

from .teacher_announcement_views import (
    TeacherAnnouncementTypesView,
    TeacherStudentAnnouncementListCreateView,
    TeacherStudentAnnouncementDetailView,
)

from chat.serializers import ChatRoomSerializer, MessageSerializer
from attendance.models import AttendanceSession, StudentAttendance, AttendanceSummary, AttendanceLeave
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.token_blacklist.models import (
    BlacklistedToken,
    OutstandingToken,
)
from django.contrib.auth.models import User
from django.db import connections
from django.utils import timezone
from django.conf import settings
from django.db.models import Prefetch, Q, Case, When, IntegerField, Count, Sum, Avg, F
from django.db.models.functions import TruncMonth, ExtractYear, ExtractMonth
from master_admin.models import School, UserProfile
from master_admin.utils import get_enabled_modules, create_user_session
from people.models import Teacher, Student
from academics.models import (
    AcademicClass,
    SubjectTeacher,
    AcademicYear,
    StudentEnrollment,
    StudentSubjectGroup,
    StudentSubject,
)
from schedules.models import TimeTable, WeekDay
from academics.year_context import get_request_academic_year, get_current_academic_year
from academics.serializers import AcademicYearSerializer
from tasks.models import (
    TaskType,
    ClassTask,
    TaskItem,
    StudentTask,
    StudentTaskItem,
    TaskSubmission,
    StudentTaskSubmission,
    SpecificStudentTask,
    SpecificStudentTaskAssignment,
    SpecificStudentTaskItem,
)
from .serializers import (
    TeacherLoginSerializer,
    VerifyTeacherOTPSerializer,
    TeacherProfileSerializer,
    ClassTeacherClassSerializer,
    SubjectTeacherInfoSerializer,
    TodayTimetableSerializer,
    TaskTypeSerializer,
    TeacherClassSerializer,
    TeacherSubjectSerializer,
    ClassTaskSerializer,
    ClassTaskDetailSerializer,
    TaskItemSerializer,
    StudentTaskListSerializer,
    StudentTaskDetailSerializer,
    GradeSubmissionSerializer,
    TaskSubmissionSerializer,
    SpecificStudentTaskSerializer,
    SpecificStudentTaskDetailSerializer,
    StudentBasicInfoSerializer,
    TeacherBasicInfoSerializer,
    AcademicClassBasicSerializer,
    SpecificStudentTaskItemSerializer,
    SpecificStudentTaskAssignmentSerializer,
    StudentAnswerDetailSerializer,
    StudentAssignmentDetailSerializer,
    GradeAnswerSerializer,
    GradeAssignmentSerializer,
    ClassStudentSerializer,
    ClassInfoSerializer,
    ClassStudentsResponseSerializer,
    SubjectStatSerializer,
    SpecificTaskStatisticsSerializer,
    TaskAssignmentListSerializer,
    TaskInfoSerializer,
    TaskAssignmentStatsSerializer,
    TaskAssignmentsResponseSerializer,
    MyTaskSerializer,
    AttendanceSessionStartSerializer,
    AttendanceSessionSerializer,
    StudentBasicAttendanceSerializer,
    StudentAttendanceSerializer,
    MarkAttendanceSerializer,
    BulkAttendanceSerializer,
    TodayAttendanceStatusSerializer,
    AttendanceHistorySerializer,
    AttendanceSummarySerializer,
    AttendanceReportFilterSerializer,
    LeaveRequestListSerializer,
    LeaveRequestDetailSerializer, 
    LeaveApproveSerializer,
    BulkLeaveActionSerializer,
    LeaveRejectSerializer
)
import logging
import json
import random
import string
import smtplib
from email.message import EmailMessage

logger = logging.getLogger(__name__)

# ── ZeptoMail config from settings.py ────────────────────────────────────────
ZEPTO_SMTP_SERVER = settings.ZEPTO_SMTP_SERVER
ZEPTO_PORT = settings.ZEPTO_PORT
ZEPTO_USERNAME = settings.ZEPTO_USERNAME
ZEPTO_PASSWORD = settings.ZEPTO_PASSWORD
ZEPTO_FROM_EMAIL = settings.ZEPTO_FROM_EMAIL
OTP_EXPIRY_MINUTES = settings.OTP_EXPIRY_MINUTES
# ─────────────────────────────────────────────────────────────────────────────


def generate_otp(length=6):
    """Generate a random numeric OTP."""
    return "".join(random.choices(string.digits, k=length))


def send_teacher_otp_email(to_email: str, otp: str, user_name: str = "") -> bool:
    """Send OTP email to teacher via ZeptoMail SMTP. Returns True on success."""
    from datetime import datetime

    current_year = datetime.now().year
    greeting = f"Dear {user_name}," if user_name else "Dear Teacher,"

    html_body = f"""
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
      </head>
      <body style="margin:0; padding:0; background-color:#f0f4ff; font-family: 'Poppins', Arial, sans-serif;">

        <table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f0f4ff; padding: 40px 0;">
          <tr>
            <td align="center">
              <table width="580" cellpadding="0" cellspacing="0" style="background-color:#ffffff; border-radius:16px; overflow:hidden; box-shadow: 0 4px 24px rgba(0,80,255,0.10);">

                <!-- HEADER -->
                <tr>
                  <td align="center" style="background: linear-gradient(135deg, #0a0a2e 0%, #0d1b6e 60%, #1a3aad 100%); padding: 36px 40px 28px 40px;">
                    <img src="https://dayscholor.com/assets/logo-CLU4khl2.png"
                         alt="DayScholor"
                         width="200"
                         style="display:block;"
                    />
                  </td>
                </tr>

                <!-- BLUE DIVIDER LINE -->
                <tr>
                  <td style="background: linear-gradient(90deg, #1a3aad, #4f8ef7, #1a3aad); height: 4px; padding:0;"></td>
                </tr>

                <!-- BODY -->
                <tr>
                  <td style="padding: 40px 44px 32px 44px;">

                    <p style="margin:0 0 6px 0; font-size:22px; font-weight:700; color:#0d1b6e; font-family:'Poppins',Arial,sans-serif;">
                      Welcome Back! 👋
                    </p>

                    <p style="margin:0 0 24px 0; font-size:14px; color:#555555; font-family:'Poppins',Arial,sans-serif; line-height:1.6;">
                      {greeting}
                    </p>

                    <p style="margin:0 0 28px 0; font-size:14px; color:#555555; font-family:'Poppins',Arial,sans-serif; line-height:1.8;">
                      Manage your classes, assignments, attendance, and student progress
                      all in one place. Use the code below to securely access your
                      <strong style="color:#0d1b6e;">DayScholor Teacher Portal</strong>.
                    </p>

                    <!-- OTP BOX -->
                    <table width="100%" cellpadding="0" cellspacing="0">
                      <tr>
                        <td align="center" style="padding: 0 0 32px 0;">
                          <table cellpadding="0" cellspacing="0">
                            <tr>
                              <td align="center" style="background: linear-gradient(135deg, #0d1b6e, #1a3aad); border-radius:12px; padding: 3px;">
                                <table cellpadding="0" cellspacing="0">
                                  <tr>
                                    <td align="center" style="background:#ffffff; border-radius:10px; padding: 24px 56px;">
                                      <p style="margin:0 0 6px 0; font-size:11px; color:#888888; letter-spacing:3px; text-transform:uppercase; font-family:'Poppins',Arial,sans-serif; font-weight:500;">
                                        Your Login Code
                                      </p>
                                      <p style="margin:0; font-size:42px; font-weight:700; color:#0d1b6e; letter-spacing:14px; font-family:'Poppins',Arial,sans-serif;">
                                        {otp}
                                      </p>
                                    </td>
                                  </tr>
                                </table>
                              </td>
                            </tr>
                          </table>
                        </td>
                      </tr>
                    </table>

                    <!-- VALIDITY BADGE -->
                    <table width="100%" cellpadding="0" cellspacing="0" style="margin-bottom:24px;">
                      <tr>
                        <td align="center">
                          <table cellpadding="0" cellspacing="0">
                            <tr>
                              <td style="background:#f0f4ff; border-left: 4px solid #1a3aad; border-radius: 4px; padding: 12px 20px;">
                                <p style="margin:0; font-size:13px; color:#0d1b6e; font-family:'Poppins',Arial,sans-serif;">
                                  ⏱ &nbsp;This code expires in <strong>{OTP_EXPIRY_MINUTES} minutes</strong>. Enter it promptly to login.
                                </p>
                              </td>
                            </tr>
                          </table>
                        </td>
                      </tr>
                    </table>

                    <p style="margin:0 0 8px 0; font-size:13px; color:#777777; font-family:'Poppins',Arial,sans-serif; line-height:1.6;">
                      🔒 &nbsp;For your security, never share this code with anyone.
                      <strong style="color:#0d1b6e;">DayScholor</strong> will never call or message you asking for this code.
                    </p>

                    <hr style="border:none; border-top:1px solid #eef0f8; margin: 28px 0;">

                    <p style="margin:0; font-size:12px; color:#aaaaaa; font-family:'Poppins',Arial,sans-serif; line-height:1.6;">
                      Didn't request this code? You can safely ignore this email —
                      your account remains secure and no action is needed.
                    </p>

                  </td>
                </tr>

                <!-- FOOTER -->
                <tr>
                  <td style="background: linear-gradient(135deg, #0a0a2e 0%, #0d1b6e 100%); padding: 24px 44px;">
                    <table width="100%" cellpadding="0" cellspacing="0">
                      <tr>
                        <td>
                          <p style="margin:0 0 4px 0; font-size:13px; color:#a0b4ff; font-family:'Poppins',Arial,sans-serif; font-weight:600;">
                            DayScholor
                          </p>
                          <p style="margin:0; font-size:11px; color:#6680cc; font-family:'Poppins',Arial,sans-serif;">
                            © {current_year} DayScholor. All rights reserved.
                          </p>
                        </td>
                        <td align="right">
                          <p style="margin:0; font-size:11px; color:#6680cc; font-family:'Poppins',Arial,sans-serif;">
                            dayscholor.com
                          </p>
                        </td>
                      </tr>
                    </table>
                  </td>
                </tr>

              </table>
            </td>
          </tr>
        </table>

      </body>
    </html>
    """

    msg = EmailMessage()
    msg["Subject"] = "Your DayScholor Login Code"
    msg["From"] = f"DayScholor <{ZEPTO_FROM_EMAIL}>"
    msg["To"] = to_email
    msg.set_content(
        f"{greeting}\n\n"
        f"Welcome back to DayScholor!\n\n"
        f"Your login code is: {otp}\n\n"
        f"Valid for {OTP_EXPIRY_MINUTES} minutes. Do not share this with anyone.\n\n"
        f"Didn't request this? You can safely ignore this email.\n\n"
        f"© {current_year} DayScholor — dayscholor.com"
    )
    msg.add_alternative(html_body, subtype="html")

    try:
        with smtplib.SMTP(ZEPTO_SMTP_SERVER, ZEPTO_PORT) as server:
            server.ehlo()
            server.starttls()
            server.ehlo()
            from master_admin.credentials import get_credential

            server.login(
                ZEPTO_USERNAME,
                get_credential("ZEPTO_PASSWORD", ZEPTO_PASSWORD),
            )
            server.send_message(msg)
        logger.info(f"Teacher OTP email sent successfully to {to_email}")
        return True
    except smtplib.SMTPAuthenticationError as e:
        logger.error(f"SMTP Authentication failed: {e}")
        return False
    except smtplib.SMTPException as e:
        logger.error(f"SMTP error: {e}")
        return False
    except Exception as e:
        logger.error(f"Unexpected error sending OTP: {e}")
        return False


class TeacherLoginView(APIView):
    """
    API endpoint for teacher login using email.
    Generates a real OTP and sends it via ZeptoMail SMTP.
    This queries the MASTER DB for User and School info.
    """

    permission_classes = [AllowAny]

    def post(self, request):
        serializer = TeacherLoginSerializer(data=request.data)

        if serializer.is_valid():
            email = serializer.validated_data["email"]

            try:
                # 1. Check if user exists in MASTER DB
                user = User.objects.get(email=email)

                # 2. Check if user is staff - teachers should be staff users
                if not user.is_staff:
                    logger.warning(
                        f"Non-staff login attempt blocked for email: {email}"
                    )
                    return Response(
                        {
                            "success": False,
                            "message": "Access denied. Only staff accounts can login as teachers.",
                        },
                        status=status.HTTP_403_FORBIDDEN,
                    )

                # 3. Get user profile from MASTER DB
                try:
                    profile = UserProfile.objects.get(user=user)
                except UserProfile.DoesNotExist:
                    return Response(
                        {"success": False, "message": "User profile not found"},
                        status=status.HTTP_404_NOT_FOUND,
                    )

                # 4. Get school info from MASTER DB
                if not profile.school:
                    return Response(
                        {
                            "success": False,
                            "message": "No school assigned to this user",
                        },
                        status=status.HTTP_404_NOT_FOUND,
                    )

                school = profile.school

                # 5. Generate OTP and send via ZeptoMail
                otp = "111111"
                user_name = f"{user.first_name} {user.last_name}".strip()
                # email_sent = send_teacher_otp_email(email, otp, user_name)
                email_sent = 1
                if not email_sent:
                    logger.error(f"Failed to send OTP email to {email}")
                    return Response(
                        {
                            "success": False,
                            "message": "Failed to send OTP. Please try again.",
                        },
                        status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    )

                # 6. Store OTP + school info in session
                request.session["pending_teacher_login"] = {
                    "email": email,
                    "user_id": user.id,
                    "school_id": school.id,
                    "school_db": school.db_name,
                    "otp": otp,  # stored server-side only
                    "otp_created_at": timezone.now().isoformat(),
                }

                logger.info(
                    f"Teacher OTP sent - User: {email}, School: {school.name}, DB: {school.db_name}"
                )

                return Response(
                    {
                        "success": True,
                        "message": "OTP sent successfully to your email",
                        "email": email,
                        "school": school.name,
                        # NOTE: otp is NOT returned in the response (security)
                    },
                    status=status.HTTP_200_OK,
                )

            except User.DoesNotExist:
                return Response(
                    {"success": False, "message": "No account found with this email"},
                    status=status.HTTP_404_NOT_FOUND,
                )

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class VerifyTeacherOTPView(APIView):
    """
    API endpoint to verify OTP and authenticate teacher.
    Validates OTP from session (server-side) and checks expiry.
    Returns JWT tokens on success.
    """

    permission_classes = [AllowAny]

    def post(self, request):
        serializer = VerifyTeacherOTPSerializer(data=request.data)

        if serializer.is_valid():
            email = serializer.validated_data["email"]
            otp = serializer.validated_data["otp"]

            try:
                # 1. Get pending login info from session
                pending = request.session.get("pending_teacher_login")
                if not pending or pending.get("email") != email:
                    return Response(
                        {
                            "success": False,
                            "message": "Login session expired. Please login again.",
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                # 2. Check OTP expiry
                from datetime import datetime, timezone as dt_timezone

                created_time = datetime.fromisoformat(pending["otp_created_at"])
                if created_time.tzinfo is None:
                    created_time = created_time.replace(tzinfo=dt_timezone.utc)
                elapsed_minutes = (timezone.now() - created_time).total_seconds() / 60

                if elapsed_minutes > OTP_EXPIRY_MINUTES:
                    del request.session["pending_teacher_login"]
                    logger.warning(
                        f"Teacher OTP expired for {email} after {elapsed_minutes:.1f} minutes"
                    )
                    return Response(
                        {
                            "success": False,
                            "message": "OTP has expired. Please login again.",
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                # 3. Verify OTP value
                if otp != pending.get("otp", ""):
                    logger.warning(f"Invalid OTP attempt for teacher {email}")
                    return Response(
                        {"success": False, "message": "Invalid OTP. Please try again."},
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                # 4. Get user from MASTER DB
                user = User.objects.get(id=pending["user_id"])

                # 5. Get school info from MASTER DB
                school = School.objects.get(id=pending["school_id"])

                # 6. Configure school DB connection
                school_db_alias = "school"
                connections[school_db_alias].settings_dict.update(
                    {
                        "NAME": school.db_name,
                        "USER": school.db_user,
                        "PASSWORD": school.db_password,
                        "HOST": school.db_host,
                        "PORT": str(school.db_port),
                    }
                )
                connections[school_db_alias].close()

                # 7. Verify teacher exists in SCHOOL DB
                try:
                    teacher = Teacher.objects.using(school_db_alias).get(
                        external_user_id=user.id
                    )
                except Teacher.DoesNotExist:
                    return Response(
                        {
                            "success": False,
                            "message": "Teacher profile not found in school database",
                        },
                        status=status.HTTP_404_NOT_FOUND,
                    )

                # 8. Generate JWT tokens with claims
                refresh = RefreshToken.for_user(user)
                refresh["school_id"] = school.id
                refresh["school_db"] = school.db_name
                refresh["user_type"] = "teacher"
                refresh["teacher_id"] = teacher.id

                # 9. Record device session
                session_obj = create_user_session(
                    request=request,
                    user=user,
                    school=school,
                    user_type="TEACHER",
                    external_id=teacher.id,
                    refresh_token=refresh,
                )

                # Embed session_token in JWT so the auth layer can invalidate it instantly
                if session_obj:
                    refresh["session_token"] = session_obj

                # 10. Clear pending session
                del request.session["pending_teacher_login"]

                logger.info(f"Teacher OTP verified successfully for {email}")

                return Response(
                    {
                        "success": True,
                        "message": "OTP verified successfully",
                        "access_token": str(refresh.access_token),
                        "refresh_token": str(refresh),
                        "expires_in": 86400,
                        "enabled_modules": get_enabled_modules(school),
                        "session_token": session_obj,
                    },
                    status=status.HTTP_200_OK,
                )

            except (User.DoesNotExist, School.DoesNotExist):
                return Response(
                    {"success": False, "message": "Authentication failed"},
                    status=status.HTTP_404_NOT_FOUND,
                )

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class TeacherLogoutView(APIView):
    """
    🔥 PROPER LOGOUT - Blacklists ALL refresh tokens for this user
    Also invalidates current access token by blacklisting its refresh token
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user

        try:
            refresh_token = request.data.get("refresh")
            tokens_blacklisted = 0

            if refresh_token:
                try:
                    token = RefreshToken(refresh_token)
                    token.blacklist()
                    tokens_blacklisted += 1
                    logger.info(
                        f"Specific refresh token blacklisted for teacher {user.id}"
                    )
                except (TokenError, InvalidToken, AttributeError) as e:
                    logger.warning(f"Failed to blacklist specific token: {e}")

            outstanding_tokens = OutstandingToken.objects.filter(user=user)

            for token in outstanding_tokens:
                try:
                    BlacklistedToken.objects.get_or_create(token=token)
                    tokens_blacklisted += 1
                except Exception as e:
                    logger.error(f"Failed to blacklist token {token.jti}: {e}")

            logger.info(
                f"Teacher {user.id} logged out. {tokens_blacklisted} tokens revoked."
            )

            return Response(
                {
                    "success": True,
                    "message": "Successfully logged out",
                    "revoked_sessions": tokens_blacklisted,
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            logger.error(f"Logout error: {str(e)}")
            return Response(
                {"success": False, "message": "Logout failed"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherProfileView(APIView):
    """
    API endpoint to get teacher profile
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            serializer = TeacherProfileSerializer(teacher)

            school = getattr(request, "school", None)
            modules = get_enabled_modules(school) if school else []

            return Response(
                {
                    "success": True,
                    "profile": serializer.data,
                    "enabled_modules": modules,
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {
                    "success": False,
                    "message": "Teacher profile not found in school database",
                },
                status=status.HTTP_404_NOT_FOUND,
            )

    def patch(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            serializer = TeacherProfileSerializer(
                teacher, data=request.data, partial=True
            )

            if serializer.is_valid():
                serializer.save()
                return Response(
                    {
                        "success": True,
                        "message": "Profile updated successfully",
                        "profile": serializer.data,
                    },
                    status=status.HTTP_200_OK,
                )

            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

class TeacherDetailView(APIView):
    """
    Comprehensive API endpoint for teacher details including:
    - Teacher profile
    - Class where teacher is class teacher
    - All subjects teacher is teaching
    - Total students in class teacher's class
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            current_academic_year = self._get_current_academic_year()

            class_teacher_info = self._get_class_teacher_info(
                teacher, current_academic_year
            )

            subjects_teaching = self._get_subjects_teaching(
                teacher, current_academic_year
            )

            # Get today's schedule count only
            today_schedule_count, schedule_summary = self._get_today_schedule_count(
                teacher
            )

            # Get full today's schedule with subject, timing, room number etc.
            today_schedule = self._get_today_schedule(teacher)

            # Get total students count + gender breakdown for class where teacher is class teacher
            total_class_students = self._get_total_class_students(
                teacher, current_academic_year
            )

            teacher_profile_serializer = TeacherProfileSerializer(teacher)

            response_data = {
                "teacher_profile": teacher_profile_serializer.data,
                "class_teacher_info": class_teacher_info,
                "subjects_teaching": subjects_teaching,
                "today_schedule_count": today_schedule_count,
                "schedule_summary": schedule_summary,
                "today_schedule": today_schedule,
                "total_class_students": total_class_students,
            }

            return Response(
                {
                    "success": True,
                    "data": response_data,
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {
                    "success": False,
                    "message": "Teacher profile not found in school database",
                },
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherDetailView: {str(e)}")
            import traceback

            logger.error(traceback.format_exc())
            return Response(
                {
                    "success": False,
                    "message": f"An error occurred: {str(e)}",
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _get_current_academic_year(self):
        try:
            # Honors the client's year selection (X-Academic-Year header),
            # falling back to the active year.
            return get_request_academic_year(self.request)
        except Exception as e:
            logger.error(f"Error fetching current academic year: {e}")
            return None

    def _get_class_teacher_info(self, teacher, academic_year):
        try:
            if not academic_year:
                return None

            academic_class = (
                AcademicClass.objects.filter(
                    class_teacher=teacher, academic_year=academic_year, is_active=True
                )
                .select_related("standard", "section", "academic_year")
                .first()
            )

            if academic_class:
                serializer = ClassTeacherClassSerializer(academic_class)
                return serializer.data

            return None

        except Exception as e:
            logger.error(f"Error getting class teacher info: {e}")
            return None

    def _get_subjects_teaching(self, teacher, academic_year):
        try:
            if not academic_year:
                return []

            subject_teachers = (
                SubjectTeacher.objects.filter(
                    teacher=teacher,
                    academic_class__academic_year=academic_year,
                    is_active=True,
                )
                .select_related(
                    "subject",
                    "subject__standard",
                    "subject__category",
                    "academic_class",
                    "academic_class__standard",
                    "academic_class__section",
                    "academic_class__academic_year",
                )
                .order_by("academic_class__standard__order")
            )

            serializer = SubjectTeacherInfoSerializer(subject_teachers, many=True)
            return serializer.data

        except Exception as e:
            logger.error(f"Error getting subjects teaching: {e}")
            return []

    def _get_total_class_students(self, teacher, academic_year):
        """
        Get total number of students enrolled in the class where teacher is class teacher,
        including gender breakdown (boys/girls/other) and class strength info.
        """
        try:
            if not academic_year:
                return {
                    "total": 0,
                    "boys": 0,
                    "girls": 0,
                    "other": 0,
                    "max_strength": 0,
                    "current_strength": 0,
                }

            # Find the academic class where this teacher is class teacher
            academic_class = (
                AcademicClass.objects.filter(
                    class_teacher=teacher, academic_year=academic_year, is_active=True
                )
                .select_related("standard", "section")
                .first()
            )

            if not academic_class:
                return {
                    "total": 0,
                    "boys": 0,
                    "girls": 0,
                    "other": 0,
                    "max_strength": 0,
                    "current_strength": 0,
                }

            # Fetch all active enrollments with student gender in one query
            enrollments = (
                StudentEnrollment.objects.filter(
                    academic_class=academic_class, is_active=True
                )
                .select_related("student")
            )

            total = enrollments.count()

            # Gender breakdown — matches whatever gender values your Student model uses
            boys = 0
            girls = 0
            other = 0

            for enrollment in enrollments:
                gender = getattr(enrollment.student, "gender", None)
                if gender:
                    gender_lower = str(gender).lower()
                    if gender_lower in ("male", "m", "boy"):
                        boys += 1
                    elif gender_lower in ("female", "f", "girl"):
                        girls += 1
                    else:
                        other += 1
                else:
                    other += 1

            return {
                "total": total,
                "boys": boys,
                "girls": girls,
                "other": other,
                "max_strength": getattr(academic_class, "max_strength", 0) or 0,
                "current_strength": getattr(academic_class, "current_strength", 0) or 0,
            }

        except Exception as e:
            logger.error(f"Error getting total class students: {e}")
            return {
                "total": 0,
                "boys": 0,
                "girls": 0,
                "other": 0,
                "max_strength": 0,
                "current_strength": 0,
            }

    def _get_today_schedule(self, teacher):
        """
        Get today's full schedule with subject, timing, room number etc.
        """
        try:
            today = timezone.now().date()
            weekday_map = {
                0: "MON", 1: "TUE", 2: "WED",
                3: "THU", 4: "FRI", 5: "SAT", 6: "SUN",
            }
            today_weekday_code = weekday_map[today.weekday()]

            try:
                weekday = WeekDay.objects.get(day_code=today_weekday_code, is_active=True)
            except WeekDay.DoesNotExist:
                return []

            if not weekday.is_open:
                return []

            academic_year = get_request_academic_year(self.request)
            if not academic_year:
                return []

            timetables = (
                TimeTable.objects.filter(
                    Q(subject_teacher__teacher=teacher) | Q(substitute_teacher=teacher),
                    weekday=weekday,
                    is_active=True,
                    academic_class__academic_year=academic_year,
                )
                .select_related(
                    "subject",
                    "academic_class",
                    "academic_class__standard",
                    "academic_class__section",
                    "weekday",
                )
                .order_by("period_number")
            )

            serializer = TodayTimetableSerializer(timetables, many=True)
            return serializer.data

        except Exception as e:
            logger.error(f"Error getting today's full schedule: {e}")
            return []

    def _get_today_schedule_count(self, teacher):
        """
        Get today's schedule count only
        """
        try:
            today = timezone.now().date()
            weekday_map = {
                0: "MON",
                1: "TUE",
                2: "WED",
                3: "THU",
                4: "FRI",
                5: "SAT",
                6: "SUN",
            }
            today_weekday_code = weekday_map[today.weekday()]

            try:
                weekday = WeekDay.objects.get(
                    day_code=today_weekday_code, is_active=True
                )
            except WeekDay.DoesNotExist:
                return 0, {
                    "message": f"No configuration for {today_weekday_code}",
                    "total_periods": 0,
                }

            if not weekday.is_open:
                return 0, {
                    "message": f"School is closed on {weekday.day_name}",
                    "day": weekday.day_name,
                    "is_open": False,
                    "total_periods": 0,
                }

            academic_year = get_request_academic_year(self.request)
            if not academic_year:
                return 0, {
                    "message": "No active academic year found",
                    "day": weekday.day_name,
                    "is_open": True,
                    "total_periods": 0,
                }

            timetables = (
                TimeTable.objects.filter(
                    Q(subject_teacher__teacher=teacher) | Q(substitute_teacher=teacher),
                    weekday=weekday,
                    is_active=True,
                    academic_class__academic_year=academic_year,
                )
                .select_related(
                    "subject",
                    "academic_class",
                    "academic_class__standard",
                    "academic_class__section",
                    "weekday",
                )
                .order_by("period_number")
            )

            total_periods = timetables.count()
            schedule_summary = {
                "day": weekday.day_name,
                "date": today,
                "is_open": True,
                "total_periods": total_periods,
                "school_start": weekday.start_time,
                "school_end": weekday.end_time,
            }

            if total_periods == 0:
                schedule_summary["message"] = "No classes scheduled for today"

            return total_periods, schedule_summary

        except Exception as e:
            logger.error(f"Error getting today's schedule count: {e}")
            return 0, {
                "message": f"Error fetching schedule: {str(e)}",
                "total_periods": 0,
            }

class TeacherTodayScheduleView(APIView):
    """
    API endpoint to get teacher's complete today's schedule
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            today_schedule, schedule_summary = self._get_today_schedule(teacher)

            response_data = {
                "today_schedule": today_schedule,
                "schedule_summary": schedule_summary,
            }

            return Response(
                {
                    "success": True,
                    "data": response_data,
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {
                    "success": False,
                    "message": "Teacher profile not found in school database",
                },
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherTodayScheduleView: {str(e)}")
            import traceback

            logger.error(traceback.format_exc())
            return Response(
                {
                    "success": False,
                    "message": f"An error occurred: {str(e)}",
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _get_today_schedule(self, teacher):
        """
        Get complete today's schedule with all period details
        """
        try:
            today = timezone.now().date()
            weekday_map = {
                0: "MON",
                1: "TUE",
                2: "WED",
                3: "THU",
                4: "FRI",
                5: "SAT",
                6: "SUN",
            }
            today_weekday_code = weekday_map[today.weekday()]

            try:
                weekday = WeekDay.objects.get(
                    day_code=today_weekday_code, is_active=True
                )
            except WeekDay.DoesNotExist:
                return [], {
                    "message": f"No configuration for {today_weekday_code}",
                    "total_periods": 0,
                }

            if not weekday.is_open:
                return [], {
                    "message": f"School is closed on {weekday.day_name}",
                    "day": weekday.day_name,
                    "is_open": False,
                    "total_periods": 0,
                }

            academic_year = get_request_academic_year(self.request)
            if not academic_year:
                return [], {
                    "message": "No active academic year found",
                    "day": weekday.day_name,
                    "is_open": True,
                    "total_periods": 0,
                }

            timetables = (
                TimeTable.objects.filter(
                    Q(subject_teacher__teacher=teacher) | Q(substitute_teacher=teacher),
                    weekday=weekday,
                    is_active=True,
                    academic_class__academic_year=academic_year,
                )
                .select_related(
                    "subject",
                    "academic_class",
                    "academic_class__standard",
                    "academic_class__section",
                    "weekday",
                )
                .order_by("period_number")
            )

            total_periods = timetables.count()
            schedule_summary = {
                "day": weekday.day_name,
                "date": today,
                "is_open": True,
                "total_periods": total_periods,
                "school_start": weekday.start_time,
                "school_end": weekday.end_time,
            }

            if total_periods == 0:
                schedule_summary["message"] = "No classes scheduled for today"

            serializer = TodayTimetableSerializer(timetables, many=True)
            return serializer.data, schedule_summary

        except Exception as e:
            logger.error(f"Error getting today's schedule: {e}")
            return [], {
                "message": f"Error fetching schedule: {str(e)}",
                "total_periods": 0,
            }


# =====================================================
# TASK TYPE API (READ-ONLY FOR TEACHERS)
# =====================================================

class TeacherClassStudentsView(APIView):
    """
    API endpoint to fetch all students in the class where teacher is class teacher
    Returns complete student details from enrollments
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            current_academic_year = self._get_current_academic_year()

            # Debug logging
            logger.info(f"Teacher: {teacher.id}")
            logger.info(
                f"Current academic year: {current_academic_year.id if current_academic_year else 'None'}"
            )

            # Get the academic class where this teacher is class teacher
            academic_class = self._get_teacher_class(teacher, current_academic_year)

            if not academic_class:
                logger.warning(
                    f"No academic class found for teacher {teacher.id} in academic year {current_academic_year}"
                )
                return Response(
                    {
                        "success": False,
                        "message": "You are not assigned as class teacher for any class in the current academic year",
                    },
                    status=status.HTTP_404_NOT_FOUND,
                )

            logger.info(f"Found academic class: {academic_class.id}")

            # Get all students enrolled in this class
            students_data = self._get_class_students(academic_class)

            logger.info(
                f"Found {len(students_data)} students in class {academic_class.id}"
            )

            response_data = {
                "class_info": {
                    "id": academic_class.id,
                    "name": f"{academic_class.standard.name} - {academic_class.section.code}",
                    "standard": academic_class.standard.name,
                    "section": academic_class.section.code,
                    "academic_year": academic_class.academic_year.name,
                    "room_number": academic_class.room_number,
                    "current_strength": academic_class.current_strength,
                    "max_strength": academic_class.max_strength,
                },
                "students": students_data,
                "total_students": len(students_data),
            }

            return Response(
                {
                    "success": True,
                    "data": response_data,
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {
                    "success": False,
                    "message": "Teacher profile not found in school database",
                },
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherClassStudentsView: {str(e)}")
            import traceback

            logger.error(traceback.format_exc())
            return Response(
                {
                    "success": False,
                    "message": f"An error occurred: {str(e)}",
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _get_current_academic_year(self):
        """
        Get the academic year the client is browsing - SAME LOGIC as TeacherDetailView
        """
        try:
            # Honors the client's year selection (X-Academic-Year header),
            # falling back to the active year.
            academic_year = get_request_academic_year(self.request)

            if academic_year:
                logger.info(
                    f"Found academic year: {academic_year.id} - {academic_year.name}"
                )
                return academic_year
            else:
                logger.warning("No active academic year found")
                return None
        except Exception as e:
            logger.error(f"Error fetching current academic year: {e}")
            return None

    def _get_teacher_class(self, teacher, academic_year):
        """
        Get the academic class where teacher is class teacher
        """
        try:
            if not academic_year:
                logger.warning("No academic year provided")
                return None

            # Query with debug info
            logger.info(
                f"Looking for AcademicClass with class_teacher={teacher.id}, academic_year={academic_year.id}, is_active=True"
            )

            academic_class = (
                AcademicClass.objects.filter(
                    class_teacher=teacher, academic_year=academic_year, is_active=True
                )
                .select_related("standard", "section", "academic_year")
                .first()
            )

            if academic_class:
                logger.info(f"Found academic class: {academic_class.id}")
            else:
                # Check if there are any classes for this teacher without academic year filter
                any_class = AcademicClass.objects.filter(
                    class_teacher=teacher, is_active=True
                ).first()
                if any_class:
                    logger.warning(
                        f"Found class for teacher but with different academic year: {any_class.academic_year.id}"
                    )
                else:
                    logger.warning(f"No class found for teacher {teacher.id} at all")

            return academic_class

        except Exception as e:
            logger.error(f"Error getting teacher class: {e}")
            return None

    def _get_class_students(self, academic_class):
        """
        Get all students enrolled in the given academic class with their details
        """
        try:
            # Get all active enrollments for this class
            logger.info(
                f"Looking for StudentEnrollment with academic_class={academic_class.id}, is_active=True"
            )

            enrollments = (
                StudentEnrollment.objects.filter(
                    academic_class=academic_class, is_active=True
                )
                .select_related("student")
                .order_by("roll_number")
            )

            logger.info(f"Found {enrollments.count()} enrollments")

            students_data = []
            for enrollment in enrollments:
                student = enrollment.student
                logger.info(
                    f"Processing student: {student.id} - {student.first_name} {student.last_name}"
                )

                # Build student details with safe attribute access
                student_info = {
                    "enrollment_id": enrollment.id,
                    "roll_number": enrollment.roll_number,
                    "admission_date": enrollment.admission_date,
                    "profile_image": student.profile_image.url if student.profile_image else None,
                    "student": {
                        "id": student.id,
                        "first_name": getattr(student, "first_name", ""),
                        "last_name": getattr(student, "last_name", ""),
                        "full_name": f"{getattr(student, 'first_name', '')} {getattr(student, 'last_name', '')}".strip(),
                    },
                }

                # Safely add optional fields
                if hasattr(student, "date_of_birth") and student.date_of_birth:
                    student_info["student"]["date_of_birth"] = student.date_of_birth

                if hasattr(student, "gender") and student.gender:
                    student_info["student"]["gender"] = student.gender

                if hasattr(student, "blood_group") and student.blood_group:
                    student_info["student"]["blood_group"] = student.blood_group

                if hasattr(student, "phone") and student.phone:
                    student_info["student"]["phone"] = student.phone

                if hasattr(student, "user") and student.user:
                    student_info["student"]["email"] = student.user.email

                if hasattr(student, "address") and student.address:
                    student_info["student"]["address"] = student.address

                if hasattr(student, "profile_url") and student.profile_url:
                    student_info["student"]["profile_url"] = student.profile_url

                # Add parent/guardian information if available
                if hasattr(student, "parent") and student.parent:
                    parent_info = {
                        "id": student.parent.id,
                        "name": f"{getattr(student.parent, 'first_name', '')} {getattr(student.parent, 'last_name', '')}".strip(),
                    }

                    if hasattr(student.parent, "phone") and student.parent.phone:
                        parent_info["phone"] = student.parent.phone

                    if hasattr(student.parent, "user") and student.parent.user:
                        parent_info["email"] = student.parent.user.email

                    if (
                        hasattr(student.parent, "relationship")
                        and student.parent.relationship
                    ):
                        parent_info["relationship"] = student.parent.relationship

                    student_info["parent"] = parent_info

                # Add selected subjects if any
                if hasattr(student, "selected_subjects") or hasattr(
                    enrollment, "selected_subjects"
                ):
                    try:
                        selected_subjects = StudentSubject.objects.filter(
                            enrollment=enrollment, is_active=True
                        ).select_related("subject")

                        if selected_subjects.exists():
                            student_info["selected_subjects"] = [
                                {
                                    "id": ss.subject.id,
                                    "name": ss.subject.name,
                                    "code": ss.subject.code,
                                    "subject_type": ss.subject.subject_type,
                                }
                                for ss in selected_subjects
                            ]
                    except Exception as e:
                        logger.error(
                            f"Error fetching subjects for enrollment {enrollment.id}: {e}"
                        )

                # Add subject group if any (for higher secondary)
                if hasattr(student, "subject_groups") or hasattr(
                    enrollment, "subject_groups"
                ):
                    try:
                        subject_groups = StudentSubjectGroup.objects.filter(
                            enrollment=enrollment, is_active=True
                        ).select_related("subject_group")

                        if subject_groups.exists():
                            student_info["subject_groups"] = [
                                {
                                    "id": sg.subject_group.id,
                                    "name": sg.subject_group.name,
                                    "code": sg.subject_group.code,
                                }
                                for sg in subject_groups
                            ]
                    except Exception as e:
                        logger.error(
                            f"Error fetching subject groups for enrollment {enrollment.id}: {e}"
                        )

                students_data.append(student_info)

            return students_data

        except Exception as e:
            logger.error(f"Error getting class students: {e}")
            import traceback

            logger.error(traceback.format_exc())
            return []


class TeacherStudentDetailView(APIView):
    """
    API endpoint for a class teacher to view full details of a single
    student (age, roll number, parent/guardian info, address, medical info,
    etc). Only accessible for students in the class where the requesting
    teacher is the class teacher.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, enrollment_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            enrollment = (
                StudentEnrollment.objects.filter(id=enrollment_id, is_active=True)
                .select_related(
                    "student",
                    "academic_class",
                    "academic_class__standard",
                    "academic_class__section",
                    "academic_class__academic_year",
                )
                .first()
            )
            if not enrollment:
                return Response(
                    {"success": False, "message": "Student enrollment not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            if enrollment.academic_class.class_teacher_id != teacher.id:
                return Response(
                    {
                        "success": False,
                        "message": "You are not the class teacher for this student",
                    },
                    status=status.HTTP_403_FORBIDDEN,
                )

            student = enrollment.student
            academic_class = enrollment.academic_class

            student_data = {
                "id": student.id,
                "full_name": student.full_name,
                "first_name": student.first_name,
                "last_name": student.last_name,
                "student_id": student.student_id,
                "date_of_birth": student.date_of_birth,
                "age": self._calculate_age(student.date_of_birth),
                "gender": student.gender,
                "blood_group": student.blood_group,
                "personal_email": student.personal_email,
                "personal_phone": student.personal_phone,
                "profile_image": (
                    student.profile_image.url if student.profile_image else None
                ),
                "admission_number": student.admission_number,
                "known_allergies": student.known_allergies,
                "medical_conditions": student.medical_conditions,
                "emergency_contact": {
                    "name": student.emergency_contact_name,
                    "phone": student.emergency_contact_phone,
                    "relation": student.emergency_contact_relation,
                },
                "permanent_address": self._format_address(
                    student.permanent_address_line_1,
                    student.permanent_address_line_2,
                    student.permanent_city,
                    student.permanent_state,
                    student.permanent_country,
                    student.permanent_pincode,
                ),
                "correspondence_address": self._format_address(
                    student.correspondence_address_line_1,
                    student.correspondence_address_line_2,
                    student.correspondence_city,
                    student.correspondence_state,
                    student.correspondence_country,
                    student.correspondence_pincode,
                ),
            }

            enrollment_data = {
                "enrollment_id": enrollment.id,
                "roll_number": enrollment.roll_number,
                "admission_date": enrollment.admission_date,
            }

            class_info = {
                "id": academic_class.id,
                "name": f"{academic_class.standard.name} - {academic_class.section.code}",
                "room_number": academic_class.room_number,
                "academic_year": academic_class.academic_year.name,
            }

            selected_subjects = [
                {
                    "id": ss.subject.id,
                    "name": ss.subject.name,
                    "code": ss.subject.code,
                }
                for ss in StudentSubject.objects.filter(
                    enrollment=enrollment, is_active=True
                ).select_related("subject")
            ]

            return Response(
                {
                    "success": True,
                    "data": {
                        "student": student_data,
                        "enrollment": enrollment_data,
                        "class_info": class_info,
                        "parents": self._get_parents(student),
                        "selected_subjects": selected_subjects,
                    },
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher profile not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherStudentDetailView: {str(e)}")
            import traceback

            logger.error(traceback.format_exc())
            return Response(
                {"success": False, "message": f"An error occurred: {str(e)}"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _calculate_age(self, date_of_birth):
        if not date_of_birth:
            return None
        today = timezone.now().date()
        age = today.year - date_of_birth.year
        if (today.month, today.day) < (date_of_birth.month, date_of_birth.day):
            age -= 1
        return age

    def _format_address(self, line1, line2, city, state, country, pincode):
        parts = [line1, line2, city, state, pincode, country]
        formatted = ", ".join(p for p in parts if p)
        return formatted or None

    def _get_parents(self, student):
        parents = []
        for sp in student.student_parents.filter(is_active=True).select_related(
            "parent"
        ):
            p = sp.parent
            parents.append(
                {
                    "id": p.id,
                    "name": p.full_name
                    or f"{p.first_name or ''} {p.last_name or ''}".strip(),
                    "relationship": sp.get_relationship_display()
                    if sp.relationship
                    else None,
                    "phone": p.phone,
                    "alternate_phone": p.alternate_phone,
                    "email": p.email,
                    "occupation": p.occupation,
                    "is_primary_contact": sp.is_primary_contact,
                }
            )
        return parents


class TaskTypeListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task_types = TaskType.objects.filter(is_active=True).order_by("name")
            serializer = TaskTypeSerializer(task_types, many=True)
            return Response(
                {"success": True, "count": task_types.count(), "data": serializer.data}
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TaskTypeListView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# TEACHER CLASSES & SUBJECTS — for dropdowns
# =====================================================


class TeacherClassesView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            today = timezone.now().date()
            academic_year = get_request_academic_year(request)

            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            all_classes = (
                AcademicClass.objects.filter(
                    Q(class_teacher=teacher)
                    | Q(
                        subject_teachers__teacher=teacher,
                        subject_teachers__is_active=True,
                    ),
                    academic_year=academic_year,
                    is_active=True,
                )
                .select_related("standard", "section")
                .distinct()
            )

            serializer = TeacherClassSerializer(all_classes, many=True)
            return Response(
                {"success": True, "count": all_classes.count(), "data": serializer.data}
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherClassesView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherSubjectsView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            class_id = request.query_params.get("class_id")

            today = timezone.now().date()
            academic_year = get_request_academic_year(request)

            subject_teachers = SubjectTeacher.objects.filter(
                teacher=teacher,
                academic_class__academic_year=academic_year,
                is_active=True,
            ).select_related(
                "subject", "academic_class__standard", "academic_class__section"
            )

            if class_id:
                subject_teachers = subject_teachers.filter(academic_class_id=class_id)

            serializer = TeacherSubjectSerializer(subject_teachers, many=True)
            return Response(
                {
                    "success": True,
                    "count": subject_teachers.count(),
                    "data": serializer.data,
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherSubjectsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# CLASS TASK CRUD
# =====================================================


class ClassTaskListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            class_id = request.query_params.get("class_id")
            subject_id = request.query_params.get("subject_id")
            task_type_id = request.query_params.get("task_type_id")
            status_filter = request.query_params.get("status")

            tasks = (
                ClassTask.objects.filter(posted_by=teacher, is_active=True)
                .select_related(
                    "academic_class__standard",
                    "academic_class__section",
                    "subject",
                    "task_type",
                )
                .annotate(
                    total_questions=Count(
                        "task_items", filter=Q(task_items__is_active=True)
                    ),
                    total_submissions=Count(
                        "submissions", filter=Q(submissions__is_active=True)
                    ),
                )
                .order_by("-created_at")
            )

            if class_id:
                tasks = tasks.filter(academic_class_id=class_id)
            if subject_id:
                tasks = tasks.filter(subject_id=subject_id)
            if task_type_id:
                tasks = tasks.filter(task_type_id=task_type_id)
            if status_filter == "published":
                tasks = tasks.filter(is_published=True)
            elif status_filter == "draft":
                tasks = tasks.filter(is_published=False)

            serializer = ClassTaskSerializer(tasks, many=True)
            return Response(
                {"success": True, "count": tasks.count(), "data": serializer.data}
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in ClassTaskListCreateView GET: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def post(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            if request.content_type and "multipart/form-data" in request.content_type:
                data = request.data.copy()
                data["posted_by"] = teacher.id
                task_items_json = data.get("task_items", "[]")
                task_items_data = json.loads(task_items_json) if task_items_json else []
                if "task_items" in data:
                    del data["task_items"]
            else:
                data = request.data.copy()
                data["posted_by"] = teacher.id
                task_items_data = data.pop("task_items", [])

            serializer = ClassTaskSerializer(data=data)
            if serializer.is_valid():
                task = serializer.save()
                if task_items_data:
                    self._create_task_items(
                        task,
                        task_items_data,
                        request.FILES if hasattr(request, "FILES") else {},
                    )
                logger.info(f"Task created: {task.id} by teacher {teacher.id}")
                return Response(
                    {
                        "success": True,
                        "message": "Task created successfully",
                        "data": ClassTaskDetailSerializer(task).data,
                    },
                    status=status.HTTP_201_CREATED,
                )

            return Response(
                {"success": False, "errors": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except json.JSONDecodeError as e:
            return Response(
                {"success": False, "message": "Invalid JSON format for task_items"},
                status=status.HTTP_400_BAD_REQUEST,
            )
        except Exception as e:
            logger.error(f"Error in ClassTaskListCreateView POST: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _create_task_items(self, class_task, task_items_data, files_dict):
        try:
            task_items = []
            for index, item_data in enumerate(task_items_data):
                attachment = None
                file_key = f"task_items[{index}][attachment]"
                if file_key in files_dict:
                    attachment = files_dict[file_key]
                elif "attachment" in item_data and item_data["attachment"]:
                    attachment = item_data["attachment"]
                task_items.append(
                    TaskItem(
                        class_task=class_task,
                        question_text=item_data.get("question_text"),
                        marks=item_data.get("marks"),
                        order=item_data.get("order", index + 1),
                        attachment=attachment,
                        is_active=True,
                    )
                )
            if task_items:
                TaskItem.objects.bulk_create(task_items)
        except Exception as e:
            logger.error(f"Error creating task items: {str(e)}")
            raise


class AIGenerateQuestionsView(APIView):
    """
    POST /teacher/ai/generate-questions/

    Generate questions using AI based on subject, standard, difficulty, and topic.

    Request Body:
    {
        "subject": "Mathematics",
        "standard": "10th",
        "difficulty": "medium",
        "topic": "Quadratic Equations",
        "num_questions": 5,
        "question_type": "mixed"  // optional: "mcq", "descriptive", "mixed"
    }

    Response:
    {
        "success": true,
        "data": {
            "subject": "Mathematics",
            "standard": "10th",
            "difficulty": "medium",
            "topic": "Quadratic Equations",
            "questions": [...]
        }
    }
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # Verify teacher
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get request parameters
            subject = request.data.get("subject")
            standard = request.data.get("standard")
            difficulty = request.data.get("difficulty", "medium")
            topic = request.data.get("topic")
            num_questions = int(request.data.get("num_questions", 5))
            question_type = request.data.get("question_type", "mixed")

            # Validate required fields
            if not subject:
                return Response(
                    {"success": False, "message": "subject is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if not standard:
                return Response(
                    {"success": False, "message": "standard is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if not topic:
                return Response(
                    {"success": False, "message": "topic is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Validate difficulty
            if difficulty not in ["easy", "medium", "hard"]:
                return Response(
                    {"success": False, "message": "difficulty must be easy, medium, or hard"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Validate num_questions
            if num_questions < 1 or num_questions > 20:
                return Response(
                    {"success": False, "message": "num_questions must be between 1 and 20"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Generate questions using AI
            questions = generate_questions_with_ai(
                subject=subject,
                standard=standard,
                difficulty=difficulty,
                topic=topic,
                num_questions=num_questions,
                question_type=question_type
            )

            return Response(
                {
                    "success": True,
                    "message": f"Generated {len(questions)} questions successfully",
                    "data": {
                        "subject": subject,
                        "standard": standard,
                        "difficulty": difficulty,
                        "topic": topic,
                        "questions": questions,
                    },
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in AIGenerateQuestionsView: {str(e)}")
            import traceback
            logger.error(traceback.format_exc())
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class AIGenerateQuestionsBatchView(APIView):
    """
    POST /teacher/ai/generate-questions-batch/

    Generate questions for multiple topics in one request.

    Request Body:
    {
        "subject": "Mathematics",
        "standard": "10th",
        "difficulty": "medium",
        "topics": ["Quadratic Equations", "Linear Equations", "Polynomials"],
        "questions_per_topic": 3
    }
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            # Verify teacher
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get request parameters
            subject = request.data.get("subject")
            standard = request.data.get("standard")
            difficulty = request.data.get("difficulty", "medium")
            topics = request.data.get("topics", [])
            questions_per_topic = int(request.data.get("questions_per_topic", 3))

            # Validate
            if not subject:
                return Response(
                    {"success": False, "message": "subject is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if not standard:
                return Response(
                    {"success": False, "message": "standard is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if not topics or not isinstance(topics, list) or len(topics) == 0:
                return Response(
                    {"success": False, "message": "topics array is required with at least one topic"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if len(topics) > 10:
                return Response(
                    {"success": False, "message": "Maximum 10 topics allowed per request"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Generate questions using batch AI
            from .utils.ai import generate_questions_batch
            result = generate_questions_batch(
                subject=subject,
                standard=standard,
                difficulty=difficulty,
                topics=topics,
                questions_per_topic=questions_per_topic
            )

            total_questions = sum(len(questions) for questions in result.values())

            return Response(
                {
                    "success": True,
                    "message": f"Generated {total_questions} questions across {len(topics)} topics",
                    "data": {
                        "subject": subject,
                        "standard": standard,
                        "difficulty": difficulty,
                        "topics": topics,
                        "generated_questions": result,
                        "total_questions": total_questions,
                    },
                },
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in AIGenerateQuestionsBatchView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
class ClassTaskDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get_object(self, task_id, teacher):
        try:
            return ClassTask.objects.get(id=task_id, posted_by=teacher, is_active=True)
        except ClassTask.DoesNotExist:
            return None

    def get(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = self.get_object(task_id, teacher)
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            return Response(
                {"success": True, "data": ClassTaskDetailSerializer(task).data}
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def patch(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = self.get_object(task_id, teacher)
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            serializer = ClassTaskSerializer(task, data=request.data, partial=True)
            if serializer.is_valid():
                serializer.save()
                return Response(
                    {
                        "success": True,
                        "message": "Task updated successfully",
                        "data": serializer.data,
                    }
                )
            return Response(
                {"success": False, "errors": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def delete(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = self.get_object(task_id, teacher)
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            task.is_active = False
            task.save()
            return Response({"success": True, "message": "Task deleted successfully"})
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TaskPublishView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            try:
                task = ClassTask.objects.get(
                    id=task_id, posted_by=teacher, is_active=True
                )
            except ClassTask.DoesNotExist:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            publish = request.data.get("publish", True)
            task.is_published = publish
            task.save()
            return Response(
                {
                    "success": True,
                    "message": f"Task {'published' if publish else 'unpublished'} successfully",
                    "data": {"id": task.id, "is_published": task.is_published},
                }
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# TASK ITEMS
# =====================================================


class TaskItemListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = ClassTask.objects.filter(
                id=task_id, posted_by=teacher, is_active=True
            ).first()
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            items = TaskItem.objects.filter(class_task=task, is_active=True).order_by(
                "order"
            )
            return Response(
                {
                    "success": True,
                    "count": items.count(),
                    "data": TaskItemSerializer(items, many=True).data,
                }
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def post(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = ClassTask.objects.filter(
                id=task_id, posted_by=teacher, is_active=True
            ).first()
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            data = request.data.copy()
            data["class_task"] = task.id
            serializer = TaskItemSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
                return Response(
                    {
                        "success": True,
                        "message": "Task item created successfully",
                        "data": serializer.data,
                    },
                    status=status.HTTP_201_CREATED,
                )
            return Response(
                {"success": False, "errors": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TaskItemDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get_object(self, item_id, teacher):
        try:
            return TaskItem.objects.select_related(
                "class_task", "class_task__posted_by"
            ).get(id=item_id, class_task__posted_by=teacher, is_active=True)
        except TaskItem.DoesNotExist:
            return None

    def patch(self, request, item_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            item = self.get_object(item_id, teacher)
            if not item:
                return Response(
                    {"success": False, "message": "Task item not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            if item.class_task.is_published:
                return Response(
                    {
                        "success": False,
                        "message": "Cannot edit items of a published task",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )
            data = request.data.copy()
            if "class_task" in data:
                del data["class_task"]
            serializer = TaskItemSerializer(item, data=data, partial=True)
            if serializer.is_valid():
                serializer.save()
                if "attachment" in request.FILES:
                    if item.attachment:
                        item.attachment.delete(save=False)
                    item.attachment = request.FILES["attachment"]
                    item.save()
                return Response(
                    {
                        "success": True,
                        "message": "Task item updated successfully",
                        "data": serializer.data,
                    }
                )
            return Response(
                {"success": False, "errors": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def delete(self, request, item_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            item = self.get_object(item_id, teacher)
            if not item:
                return Response(
                    {"success": False, "message": "Task item not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            if item.class_task.is_published:
                return Response(
                    {
                        "success": False,
                        "message": "Cannot delete items from a published task",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )
            if item.student_answers.filter(is_active=True).exists():
                return Response(
                    {
                        "success": False,
                        "message": "Cannot delete question that has student answers",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )
            item.is_active = False
            item.save()
            return Response(
                {"success": True, "message": "Task item deleted successfully"}
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# MY TASKS — teacher's own tasks with filters
# =====================================================


class MyTasksView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            class_id = request.query_params.get("class_id")
            subject_id = request.query_params.get("subject_id")
            task_type_id = request.query_params.get("task_type_id")
            from_date = request.query_params.get("from_date")
            to_date = request.query_params.get("to_date")
            date_field = request.query_params.get("date_field", "created")
            status_filter = request.query_params.get("status")

            tasks = (
                ClassTask.objects.filter(posted_by=teacher, is_active=True)
                .select_related(
                    "academic_class__standard",
                    "academic_class__section",
                    "academic_class__academic_year",
                    "subject",
                    "task_type",
                    "posted_by",
                )
                .annotate(
                    total_questions=Count(
                        "task_items", filter=Q(task_items__is_active=True)
                    ),
                    total_submissions=Count(
                        "submissions", filter=Q(submissions__is_active=True)
                    ),
                    checked_submissions=Count(
                        "submissions",
                        filter=Q(
                            submissions__is_active=True, submissions__status="CHECKED"
                        ),
                    ),
                )
                .order_by("-created_at")
            )

            if class_id:
                tasks = tasks.filter(academic_class_id=class_id)
            if subject_id:
                tasks = tasks.filter(subject_id=subject_id)
            if task_type_id:
                tasks = tasks.filter(task_type_id=task_type_id)
            if status_filter == "published":
                tasks = tasks.filter(is_published=True)
            elif status_filter == "draft":
                tasks = tasks.filter(is_published=False)

            if date_field == "due":
                if from_date:
                    tasks = tasks.filter(due_date__gte=from_date)
                if to_date:
                    tasks = tasks.filter(due_date__lte=to_date)
            else:
                if from_date:
                    tasks = tasks.filter(created_at__date__gte=from_date)
                if to_date:
                    tasks = tasks.filter(created_at__date__lte=to_date)

            return Response(
                {
                    "success": True,
                    "count": tasks.count(),
                    "filters_applied": {
                        "class_id": class_id,
                        "subject_id": subject_id,
                        "task_type_id": task_type_id,
                        "from_date": from_date,
                        "to_date": to_date,
                        "date_field": date_field,
                        "status": status_filter,
                    },
                    "data": MyTaskSerializer(tasks, many=True).data,
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in MyTasksView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# CLASS TASK SUBMISSIONS — teacher reviews who submitted
# =====================================================


class ClassTaskSubmissionsView(APIView):
    """
    GET /tasks/<task_id>/submissions/
    Returns all students in the class with their submission status.
    Students who haven't submitted show status=PENDING.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            task = (
                ClassTask.objects.filter(id=task_id, posted_by=teacher, is_active=True)
                .select_related("academic_class")
                .first()
            )

            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # All students in the class
            enrollments = (
                StudentEnrollment.objects.filter(
                    academic_class=task.academic_class, is_active=True
                )
                .select_related("student")
                .order_by("roll_number")
            )

            # All submissions for this task — one query
            submissions = TaskSubmission.objects.filter(
                task=task, is_active=True
            ).select_related("enrollment__student", "checked_by")
            submission_map = {s.enrollment_id: s for s in submissions}

            students_data = []
            for enrollment in enrollments:
                sub = submission_map.get(enrollment.id)
                students_data.append(
                    {
                        "enrollment_id": enrollment.id,
                        "student_id": enrollment.student.id,
                        "student_name": enrollment.student.full_name
                        or f"{enrollment.student.first_name} {enrollment.student.last_name}".strip(),
                        "roll_number": enrollment.roll_number,
                        "submission_id": (
                            sub.id if sub else None
                        ),  # ← use this to open submission detail
                        "submission_status": sub.status if sub else "PENDING",
                        "submitted_at": sub.submitted_at if sub else None,
                        "marks_obtained": (
                            float(sub.marks_obtained)
                            if sub and sub.marks_obtained
                            else None
                        ),
                        "checked_by": (
                            f"{sub.checked_by.first_name} {sub.checked_by.last_name}".strip()
                            if sub and sub.checked_by
                            else None
                        ),
                        "checked_at": sub.checked_at if sub else None,
                        "remarks": sub.remarks if sub else None,
                    }
                )

            total_students = len(students_data)
            submitted_count = len(
                [s for s in submissions if s.status in ["SUBMITTED", "CHECKED", "LATE"]]
            )
            checked_count = len([s for s in submissions if s.status == "CHECKED"])

            return Response(
                {
                    "success": True,
                    "data": {
                        "task_info": {
                            "id": task.id,
                            "title": task.title,
                            "total_marks": task.total_marks,
                            "due_date": task.due_date,
                            "is_published": task.is_published,
                        },
                        "statistics": {
                            "total_students": total_students,
                            "submitted": submitted_count,
                            "checked": checked_count,
                            "pending": total_students - submitted_count,
                            "submission_percentage": (
                                round(submitted_count / total_students * 100, 2)
                                if total_students > 0
                                else 0
                            ),
                        },
                        "students": students_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in ClassTaskSubmissionsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# SUBMISSION DETAIL — teacher views one student's answers
# =====================================================


class SubmissionDetailView(APIView):
    """
    GET  /submissions/<submission_id>/        — view student's answers
    POST /submissions/<submission_id>/grade/  — grade the submission
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, submission_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            submission = (
                TaskSubmission.objects.filter(
                    id=submission_id,
                    task__posted_by=teacher,
                    is_active=True,
                )
                .select_related("enrollment__student", "task", "checked_by")
                .first()
            )

            if not submission:
                return Response(
                    {"success": False, "message": "Submission not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get StudentTask — holds the actual answers
            student_task = StudentTask.objects.filter(
                class_task=submission.task,
                enrollment=submission.enrollment,
                is_active=True,
            ).first()

            # Build answer map keyed by task_item_id
            answer_map = {}
            if student_task:
                answers = StudentTaskItem.objects.filter(
                    student_task=student_task,
                ).values(
                    "id",
                    "task_item_id",
                    "answer_text",
                    "answer_file",
                    "marks_obtained",
                    "teacher_remark",
                    "submitted_at",
                )
                answer_map = {a["task_item_id"]: a for a in answers}

            # All questions for this task
            questions = TaskItem.objects.filter(
                class_task=submission.task, is_active=True
            ).order_by("order")

            answers_data = []
            for q in questions:
                ans = answer_map.get(q.id)
                answers_data.append(
                    {
                        "question_id": q.id,
                        "question_text": q.question_text,
                        "question_order": q.order,
                        "max_marks": q.marks,
                        "attachment": q.attachment.url if q.attachment else None,
                        "answer_text": ans["answer_text"] if ans else None,
                        "answer_file": ans["answer_file"] if ans else None,
                        "marks_obtained": (
                            float(ans["marks_obtained"])
                            if ans and ans["marks_obtained"]
                            else None
                        ),
                        "teacher_remark": ans["teacher_remark"] if ans else None,
                        "submitted_at": ans["submitted_at"] if ans else None,
                    }
                )

            return Response(
                {
                    "success": True,
                    "data": {
                        "submission_id": submission.id,
                        "task_id": submission.task.id,
                        "task_title": submission.task.title,
                        "total_marks": submission.task.total_marks,
                        "student_id": submission.enrollment.student.id,
                        "student_name": submission.enrollment.student.full_name
                        or f"{submission.enrollment.student.first_name} {submission.enrollment.student.last_name}".strip(),
                        "roll_number": submission.enrollment.roll_number,
                        "status": submission.status,
                        "submitted_at": submission.submitted_at,
                        "marks_obtained": (
                            float(submission.marks_obtained)
                            if submission.marks_obtained
                            else None
                        ),
                        "checked_by": (
                            f"{submission.checked_by.first_name} {submission.checked_by.last_name}".strip()
                            if submission.checked_by
                            else None
                        ),
                        "checked_at": submission.checked_at,
                        "remarks": submission.remarks,
                        "answers": answers_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in SubmissionDetailView GET: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# GRADE SUBMISSION
# =====================================================


class GradeSubmissionView(APIView):
    """
    POST /submissions/<submission_id>/grade/

    Body:
    {
        "marks_obtained": 45,
        "remarks": "Good work",
        "question_marks": [          // optional — grade per question
            { "question_id": 3, "marks_obtained": 8, "remark": "Correct" },
            { "question_id": 4, "marks_obtained": 7, "remark": "Partially correct" }
        ]
    }
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, submission_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            submission = (
                TaskSubmission.objects.filter(
                    id=submission_id, task__posted_by=teacher, is_active=True
                )
                .select_related("task")
                .first()
            )

            if not submission:
                return Response(
                    {"success": False, "message": "Submission not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            marks_obtained = request.data.get("marks_obtained")
            remarks = request.data.get("remarks", "")
            question_marks = request.data.get("question_marks", [])

            if marks_obtained and float(marks_obtained) > submission.task.total_marks:
                return Response(
                    {
                        "success": False,
                        "message": f"Marks ({marks_obtained}) cannot exceed total marks ({submission.task.total_marks})",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if marks_obtained:
                submission.marks_obtained = marks_obtained
            submission.checked_by = teacher
            submission.checked_at = timezone.now()
            submission.status = "CHECKED"
            submission.remarks = remarks
            submission.save()

            # Grade per question if provided
            if question_marks:
                student_task = StudentTask.objects.filter(
                    class_task=submission.task,
                    enrollment=submission.enrollment,
                    is_active=True,
                ).first()
                if student_task:
                    for q in question_marks:
                        StudentTaskItem.objects.filter(
                            student_task=student_task,
                            task_item_id=q.get("question_id"),
                            is_active=True,
                        ).update(
                            marks_obtained=q.get("marks_obtained"),
                            teacher_remark=q.get("remark", ""),
                        )

            return Response(
                {
                    "success": True,
                    "message": "Submission graded successfully",
                    "data": {
                        "submission_id": submission.id,
                        "status": submission.status,
                        "marks_obtained": (
                            float(submission.marks_obtained)
                            if submission.marks_obtained
                            else None
                        ),
                        "checked_at": submission.checked_at,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in GradeSubmissionView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# SPECIFIC STUDENT TASKS
# =====================================================


class ClassStudentsForTaskView(APIView):
    """GET /classes/<class_id>/students/ — pick students to assign specific task"""

    permission_classes = [IsAuthenticated]

    def get(self, request, class_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            has_access = AcademicClass.objects.filter(
                Q(class_teacher=teacher) | Q(subject_teachers__teacher=teacher),
                id=class_id,
                is_active=True,
            ).exists()

            if not has_access:
                return Response(
                    {
                        "success": False,
                        "message": "You don't have access to this class",
                    },
                    status=status.HTTP_403_FORBIDDEN,
                )

            enrollments = (
                StudentEnrollment.objects.filter(
                    academic_class_id=class_id, is_active=True
                )
                .select_related(
                    "student", "academic_class__standard", "academic_class__section"
                )
                .order_by("roll_number")
            )

            students_data = [
                {
                    "enrollment_id": e.id,
                    "student_id": e.student.id,
                    "student_name": e.student.full_name
                    or f"{e.student.first_name} {e.student.last_name}".strip(),
                    "roll_number": e.roll_number,
                    "admission_number": e.student.admission_number,
                }
                for e in enrollments
            ]

            academic_class = (
                enrollments.first().academic_class if enrollments.exists() else None
            )

            return Response(
                {
                    "success": True,
                    "data": {
                        "class_info": {
                            "id": class_id,
                            "standard": (
                                academic_class.standard.name if academic_class else None
                            ),
                            "section": (
                                academic_class.section.name if academic_class else None
                            ),
                            "total_students": len(students_data),
                        },
                        "students": students_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class SpecificStudentTaskListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            class_id = request.query_params.get("class_id")
            student_id = request.query_params.get("student_id")
            subject_id = request.query_params.get("subject_id")
            status_filter = request.query_params.get("status")

            tasks = (
                SpecificStudentTask.objects.filter(created_by=teacher, is_active=True)
                .annotate(
                    total_questions=Count(
                        "task_items", filter=Q(task_items__assignment=None)
                    ),
                    assigned_students=Count("assignments"),
                    submitted_count=Count(
                        "assignments", filter=Q(assignments__status="SUBMITTED")
                    ),
                    graded_count=Count(
                        "assignments", filter=Q(assignments__status="GRADED")
                    ),
                )
                .order_by("-created_at")
            )

            if class_id:
                tasks = tasks.filter(assignments__academic_class_id=class_id).distinct()
            if student_id:
                tasks = tasks.filter(assignments__student_id=student_id)
            if subject_id:
                tasks = tasks.filter(subject_id=subject_id)
            if status_filter == "pending":
                tasks = tasks.filter(assignments__status="PENDING")
            elif status_filter == "submitted":
                tasks = tasks.filter(assignments__status="SUBMITTED")
            elif status_filter == "graded":
                tasks = tasks.filter(assignments__status="GRADED")

            return Response(
                {
                    "success": True,
                    "count": tasks.count(),
                    "data": SpecificStudentTaskSerializer(tasks, many=True).data,
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in SpecificStudentTaskListCreateView GET: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def post(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            if request.content_type and "multipart/form-data" in request.content_type:
                data = request.data.copy()
                student_ids = json.loads(data.get("student_ids", "[]"))
                questions = json.loads(data.get("questions", "[]"))
                class_id = data.get("class_id")
                for key in ["student_ids", "questions", "class_id"]:
                    if key in data:
                        del data[key]
            else:
                data = request.data
                student_ids = data.get("student_ids", [])
                questions = data.get("questions", [])
                class_id = data.get("class_id")

            if not student_ids:
                return Response(
                    {
                        "success": False,
                        "message": "At least one student must be selected",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )
            if not class_id:
                return Response(
                    {"success": False, "message": "Class ID is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            specific_task_data = {
                "created_by": teacher.id,
                "title": data.get("title"),
                "description": data.get("description"),
                "subject_id": data.get("subject_id"),
                "due_date": data.get("due_date"),
                "total_marks": data.get("total_marks"),
                "is_active": True,
            }
            if "document" in request.FILES:
                specific_task_data["document"] = request.FILES["document"]

            task_serializer = SpecificStudentTaskSerializer(data=specific_task_data)
            if not task_serializer.is_valid():
                return Response(
                    {"success": False, "errors": task_serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            specific_task = task_serializer.save()

            if questions:
                self._create_task_items(specific_task, questions, request.FILES)

            assignments = self._assign_to_students(specific_task, student_ids, class_id)

            return Response(
                {
                    "success": True,
                    "message": f"Task created and assigned to {len(assignments)} students",
                    "data": SpecificStudentTaskDetailSerializer(specific_task).data,
                },
                status=status.HTTP_201_CREATED,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except json.JSONDecodeError:
            return Response(
                {"success": False, "message": "Invalid JSON format"},
                status=status.HTTP_400_BAD_REQUEST,
            )
        except Exception as e:
            logger.error(f"Error in SpecificStudentTaskListCreateView POST: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _create_task_items(self, specific_task, questions, files_dict):
        try:
            items = []
            for i, q in enumerate(questions):
                attachment = files_dict.get(f"questions[{i}][attachment]")
                items.append(
                    SpecificStudentTaskItem(
                        specific_task=specific_task,
                        assignment=None,  # master question
                        question_text=q.get("question_text"),
                        marks=q.get("marks"),
                        order=q.get("order", i + 1),
                        attachment=attachment,
                    )
                )
            if items:
                SpecificStudentTaskItem.objects.bulk_create(items)
        except Exception as e:
            logger.error(f"Error creating specific task items: {str(e)}")
            raise

    def _assign_to_students(self, specific_task, student_ids, class_id):
        try:
            enrollments = StudentEnrollment.objects.filter(
                student_id__in=student_ids, academic_class_id=class_id, is_active=True
            ).select_related("student", "academic_class")

            if not enrollments:
                raise Exception("No valid student enrollments found")

            # Create assignments
            assignment_objs = [
                SpecificStudentTaskAssignment(
                    specific_task=specific_task,
                    student=e.student,
                    enrollment=e,
                    academic_class=e.academic_class,
                    status="PENDING",
                )
                for e in enrollments
            ]
            created = SpecificStudentTaskAssignment.objects.bulk_create(assignment_objs)

            # Create answer copy rows per student per question
            master_questions = specific_task.task_items.filter(assignment=None)
            if master_questions.exists():
                answer_copies = [
                    SpecificStudentTaskItem(
                        specific_task=specific_task,
                        assignment=assignment,
                        question_text=q.question_text,
                        marks=q.marks,
                        order=q.order,
                        attachment=q.attachment,
                    )
                    for assignment in created
                    for q in master_questions
                ]
                if answer_copies:
                    SpecificStudentTaskItem.objects.bulk_create(answer_copies)

            return created
        except Exception as e:
            logger.error(f"Error assigning to students: {str(e)}")
            raise


class SpecificStudentTaskDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get_object(self, task_id, teacher):
        try:
            return (
                SpecificStudentTask.objects.select_related("created_by", "subject")
                .prefetch_related(
                    Prefetch(
                        "task_items",
                        queryset=SpecificStudentTaskItem.objects.filter(
                            assignment=None
                        ).order_by("order"),
                    ),
                    Prefetch(
                        "assignments",
                        queryset=SpecificStudentTaskAssignment.objects.select_related(
                            "student",
                            "enrollment",
                            "academic_class__standard",
                            "academic_class__section",
                        ),
                    ),
                )
                .get(id=task_id, created_by=teacher, is_active=True)
            )
        except SpecificStudentTask.DoesNotExist:
            return None

    def get(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = self.get_object(task_id, teacher)
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            return Response(
                {
                    "success": True,
                    "data": SpecificStudentTaskDetailSerializer(task).data,
                }
            )
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def delete(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            task = self.get_object(task_id, teacher)
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )
            task.is_active = False
            task.save()
            return Response({"success": True, "message": "Task deleted successfully"})
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# SPECIFIC TASK — all assignments (who submitted)
# =====================================================


class SpecificTaskAssignmentsView(APIView):
    """
    GET /specific-tasks/<task_id>/assignments/
    Shows all students this task was assigned to + their status.
    Use assignment_id to open SpecificStudentTaskAnswerView.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, task_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            task = SpecificStudentTask.objects.filter(
                id=task_id, created_by=teacher, is_active=True
            ).first()
            if not task:
                return Response(
                    {"success": False, "message": "Task not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            assignments = (
                SpecificStudentTaskAssignment.objects.filter(specific_task=task)
                .select_related(
                    "student",
                    "enrollment",
                    "academic_class__standard",
                    "academic_class__section",
                )
                .annotate(
                    answers_submitted=Count(
                        "answers",
                        filter=Q(answers__answer_text__isnull=False)
                        | Q(answers__answer_file__isnull=False),
                    ),
                    total_marks_obtained=Sum("answers__marks_obtained"),
                )
                .order_by("student__first_name")
            )

            assignments_data = [
                {
                    "assignment_id": a.id,  # ← use this for answer/grade view
                    "student_id": a.student.id,
                    "student_name": a.student.full_name
                    or f"{a.student.first_name} {a.student.last_name}".strip(),
                    "roll_number": a.enrollment.roll_number if a.enrollment else None,
                    "status": a.status,
                    "assigned_at": a.assigned_at,
                    "answers_submitted": a.answers_submitted,
                    "total_marks_obtained": (
                        float(a.total_marks_obtained)
                        if a.total_marks_obtained
                        else None
                    ),
                }
                for a in assignments
            ]

            total = len(assignments_data)
            submitted = assignments.filter(status="SUBMITTED").count()
            graded = assignments.filter(status="GRADED").count()
            pending = assignments.filter(status="PENDING").count()

            return Response(
                {
                    "success": True,
                    "data": {
                        "task_info": {
                            "id": task.id,
                            "title": task.title,
                            "total_marks": task.total_marks,
                            "due_date": task.due_date,
                            "total_questions": task.task_items.filter(
                                assignment=None
                            ).count(),
                        },
                        "statistics": {
                            "total_assigned": total,
                            "submitted": submitted,
                            "graded": graded,
                            "pending": pending,
                            "submission_percentage": (
                                round((submitted + graded) / total * 100, 2)
                                if total > 0
                                else 0
                            ),
                        },
                        "assignments": assignments_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in SpecificTaskAssignmentsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# SPECIFIC TASK ANSWER DETAIL + GRADE
# =====================================================


class SpecificStudentTaskAnswerView(APIView):
    """
    GET  /specific-assignments/<assignment_id>/answers/ — view student's answers
    POST /specific-assignments/<assignment_id>/grade/   — grade the answers
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, assignment_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            assignment = (
                SpecificStudentTaskAssignment.objects.filter(
                    id=assignment_id,
                    specific_task__created_by=teacher,
                )
                .select_related("student", "specific_task", "enrollment")
                .first()
            )

            if not assignment:
                return Response(
                    {"success": False, "message": "Assignment not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Answer copy rows for this student
            answers = SpecificStudentTaskItem.objects.filter(
                assignment=assignment,
            ).order_by("order")

            answers_data = [
                {
                    "answer_id": a.id,
                    "question_text": a.question_text,
                    "question_order": a.order,
                    "max_marks": a.marks,
                    "answer_text": a.answer_text,
                    "answer_file": a.answer_file.url if a.answer_file else None,
                    "marks_obtained": (
                        float(a.marks_obtained) if a.marks_obtained else None
                    ),
                    "teacher_remark": a.teacher_remark,
                    "submitted_at": a.submitted_at,
                }
                for a in answers
            ]

            total_obtained = sum(
                a["marks_obtained"] for a in answers_data if a["marks_obtained"]
            )

            return Response(
                {
                    "success": True,
                    "data": {
                        "assignment_info": {
                            "assignment_id": assignment.id,
                            "student_id": assignment.student.id,
                            "student_name": assignment.student.full_name
                            or f"{assignment.student.first_name} {assignment.student.last_name}".strip(),
                            "task_id": assignment.specific_task.id,
                            "task_title": assignment.specific_task.title,
                            "total_marks": assignment.specific_task.total_marks,
                            "status": assignment.status,
                            "assigned_at": assignment.assigned_at,
                            "total_obtained": float(total_obtained),
                        },
                        "answers": answers_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in SpecificStudentTaskAnswerView GET: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def post(self, request, assignment_id):
        """
        Body:
        {
            "answers": [
                { "answer_id": 7, "marks_obtained": 8.5, "teacher_remark": "Good" }
            ],
            "overall_remarks": "Well done"
        }
        """
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            assignment = (
                SpecificStudentTaskAssignment.objects.filter(
                    id=assignment_id,
                    specific_task__created_by=teacher,
                )
                .select_related("specific_task")
                .first()
            )

            if not assignment:
                return Response(
                    {"success": False, "message": "Assignment not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            answers_data = request.data.get("answers", [])
            if not answers_data:
                return Response(
                    {"success": False, "message": "No answers data provided"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            total_obtained = 0
            updated_count = 0
            errors = []

            for ans in answers_data:
                answer_id = ans.get("answer_id")
                marks = ans.get("marks_obtained")
                remark = ans.get("teacher_remark", "")

                try:
                    answer = SpecificStudentTaskItem.objects.get(
                        id=answer_id, assignment=assignment
                    )
                    # Validate max marks
                    if marks and answer.marks and float(marks) > float(answer.marks):
                        errors.append(
                            {
                                "answer_id": answer_id,
                                "error": f"Marks exceed maximum ({answer.marks}) for Q{answer.order}",
                            }
                        )
                        continue

                    answer.marks_obtained = marks
                    answer.teacher_remark = remark
                    answer.save()

                    if marks:
                        total_obtained += float(marks)
                    updated_count += 1

                except SpecificStudentTaskItem.DoesNotExist:
                    errors.append({"answer_id": answer_id, "error": "Answer not found"})

            # Mark assignment as GRADED
            assignment.status = "GRADED"
            assignment.save(update_fields=["status"])

            return Response(
                {
                    "success": True,
                    "message": f"Graded {updated_count} answers",
                    "data": {
                        "assignment_id": assignment.id,
                        "status": assignment.status,
                        "total_marks_obtained": total_obtained,
                        "updated_count": updated_count,
                        "errors": errors if errors else None,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in SpecificStudentTaskAnswerView POST: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TodayAttendanceStatusView(APIView):
    """
    GET /teacher/attendance/today/status/

    Checks if teacher has taken attendance today.
    For class teacher only - one attendance per day.
    Returns:
    - has_taken_attendance: boolean
    - session_id: if exists
    - academic_class: class info
    - total_students and marked_count
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            today = timezone.now().date()

            # Get current academic year
            academic_year = get_request_academic_year(self.request)

            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Check if teacher is class teacher for any class
            class_teacher_class = (
                AcademicClass.objects.filter(
                    class_teacher=teacher, academic_year=academic_year, is_active=True
                )
                .select_related("standard", "section")
                .first()
            )

            if not class_teacher_class:
                return Response(
                    {
                        "success": False,
                        "message": "You are not a class teacher for any active class",
                        "has_taken_attendance": False,
                        "session_id": None,
                    },
                    status=status.HTTP_200_OK,
                )

            # Check if attendance already taken today
            existing_session = AttendanceSession.objects.filter(
                academic_class=class_teacher_class,
                date=today,
                session_type="FULL_DAY",  # Full day attendance only
                is_active=True,
            ).first()

            # Get total students in class
            total_students = StudentEnrollment.objects.filter(
                academic_class=class_teacher_class, is_active=True
            ).count()

            marked_count = 0
            if existing_session:
                marked_count = StudentAttendance.objects.filter(
                    session=existing_session, is_active=True
                ).count()

            response_data = {
                "success": True,
                "has_taken_attendance": existing_session is not None,
                "session_id": existing_session.id if existing_session else None,
                "session_status": existing_session.status if existing_session else None,
                "academic_class": {
                    "id": class_teacher_class.id,
                    "name": str(class_teacher_class),
                    "standard": class_teacher_class.standard.name,
                    "section": (
                        class_teacher_class.section.name
                        if class_teacher_class.section
                        else None
                    ),
                },
                "date": today,
                "total_students": total_students,
                "marked_count": marked_count,
                "message": (
                    "Attendance already taken for today"
                    if existing_session
                    else "No attendance taken for today"
                ),
            }

            if existing_session:
                response_data["attendance_summary"] = {
                    "present": existing_session.present_count,
                    "absent": existing_session.absent_count,
                    "late": existing_session.late_count,
                    "leave": existing_session.leave_count,
                }

            return Response(response_data, status=status.HTTP_200_OK)

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TodayAttendanceStatusView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class StartAttendanceView(APIView):
    """
    POST /teacher/attendance/start/

    Start a new attendance session for today.
    Validates:
    - Teacher is class teacher
    - No existing session for today
    - Academic year is active
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            today = timezone.now().date()

            serializer = AttendanceSessionStartSerializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"success": False, "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            academic_class_id = serializer.validated_data["academic_class_id"]
            remarks = serializer.validated_data.get("remarks", "")
            session_date = serializer.validated_data.get("date", today)

            # Verify teacher is class teacher
            academic_class = (
                AcademicClass.objects.filter(
                    id=academic_class_id, class_teacher=teacher, is_active=True
                )
                .select_related("standard", "section")
                .first()
            )

            if not academic_class:
                return Response(
                    {
                        "success": False,
                        "message": "You are not the class teacher for this class",
                    },
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Check for existing session
            existing_session = AttendanceSession.objects.filter(
                academic_class=academic_class,
                date=session_date,
                session_type="FULL_DAY",
                is_active=True,
            ).first()

            if existing_session:
                return Response(
                    {
                        "success": False,
                        "message": "Attendance already taken for this date",
                        "session_id": existing_session.id,
                        "session_status": existing_session.status,
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Get total students
            total_students = StudentEnrollment.objects.filter(
                academic_class=academic_class, is_active=True
            ).count()

            # Create attendance session
            with transaction.atomic():
                session = AttendanceSession.objects.create(
                    academic_class=academic_class,
                    taken_by=teacher,
                    date=session_date,
                    session_type="FULL_DAY",
                    status="OPEN",
                    total_students=total_students,
                    remarks=remarks,
                )

                logger.info(
                    f"Attendance session created: {session.id} by teacher {teacher.id}"
                )

            return Response(
                {
                    "success": True,
                    "message": "Attendance session started successfully",
                    "data": AttendanceSessionSerializer(session).data,
                },
                status=status.HTTP_201_CREATED,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in StartAttendanceView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class AttendanceSessionDetailView(APIView):
    """
    GET /teacher/attendance/session/<session_id>/

    Get detailed attendance session with student list and current marks.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, session_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            session = (
                AttendanceSession.objects.filter(
                    id=session_id, taken_by=teacher, is_active=True
                )
                .select_related("academic_class__standard", "academic_class__section")
                .first()
            )

            if not session:
                return Response(
                    {"success": False, "message": "Attendance session not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get all students in class with their attendance status
            enrollments = (
                StudentEnrollment.objects.filter(
                    academic_class=session.academic_class, is_active=True
                )
                .select_related("student")
                .order_by("roll_number")
            )

            # Get existing attendance records
            attendance_records = StudentAttendance.objects.filter(
                session=session, is_active=True
            ).select_related("student")

            attendance_map = {a.enrollment_id: a for a in attendance_records}

            students_data = []
            for enrollment in enrollments:
                attendance = attendance_map.get(enrollment.id)
                students_data.append(
                    {
                        "enrollment_id": enrollment.id,
                        "student_id": enrollment.student.id,
                        "student_name": enrollment.student.full_name
                        or f"{enrollment.student.first_name} {enrollment.student.last_name}".strip(),
                        "roll_number": enrollment.roll_number,
                        "admission_number": enrollment.student.admission_number,
                        "attendance_id": attendance.id if attendance else None,
                        "status": attendance.status if attendance else "PENDING",
                        "remarks": attendance.remarks if attendance else "",
                        "late_minutes": attendance.late_minutes if attendance else None,
                        "marked_at": attendance.marked_at if attendance else None,
                    }
                )

            return Response(
                {
                    "success": True,
                    "data": {
                        "session": AttendanceSessionSerializer(session).data,
                        "students": students_data,
                        "statistics": {
                            "total": session.total_students,
                            "marked": len(attendance_records),
                            "present": session.present_count,
                            "absent": session.absent_count,
                            "late": session.late_count,
                            "leave": session.leave_count,
                            "pending": session.total_students - len(attendance_records),
                        },
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in AttendanceSessionDetailView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class MarkStudentAttendanceView(APIView):
    """
    POST /teacher/attendance/session/<session_id>/mark/

    Mark attendance for a single student.
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, session_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            session = AttendanceSession.objects.filter(
                id=session_id, taken_by=teacher, is_active=True
            ).first()

            if not session:
                return Response(
                    {"success": False, "message": "Attendance session not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            if session.status != "OPEN":
                return Response(
                    {
                        "success": False,
                        "message": f"Cannot modify attendance in {session.status} state",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            serializer = MarkAttendanceSerializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"success": False, "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            data = serializer.validated_data

            # Verify enrollment belongs to this class
            enrollment = (
                StudentEnrollment.objects.filter(
                    id=data["enrollment_id"],
                    academic_class=session.academic_class,
                    is_active=True,
                )
                .select_related("student")
                .first()
            )

            if not enrollment:
                return Response(
                    {"success": False, "message": "Student not found in this class"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Create or update attendance
            with transaction.atomic():
                attendance, created = StudentAttendance.objects.update_or_create(
                    session=session,
                    enrollment=enrollment,
                    defaults={
                        "student": enrollment.student,
                        "status": data["status"],
                        "remarks": data.get("remarks", ""),
                        "late_minutes": data.get("late_minutes"),
                        "marked_by": teacher,
                    },
                )

                # Session counts are updated via save() signal

                logger.info(
                    f"Attendance marked: {attendance.id} for student {enrollment.student.id}"
                )

            return Response(
                {
                    "success": True,
                    "message": "Attendance marked successfully",
                    "data": StudentAttendanceSerializer(attendance).data,
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in MarkStudentAttendanceView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class BulkMarkAttendanceView(APIView):
    """
    POST /teacher/attendance/session/<session_id>/bulk-mark/

    Mark attendance for multiple students in one request.
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, session_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            session = AttendanceSession.objects.filter(
                id=session_id, taken_by=teacher, is_active=True
            ).first()

            if not session:
                return Response(
                    {"success": False, "message": "Attendance session not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            if session.status != "OPEN":
                return Response(
                    {
                        "success": False,
                        "message": f"Cannot modify attendance in {session.status} state",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            serializer = BulkAttendanceSerializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"success": False, "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            attendance_data = serializer.validated_data["attendance_data"]

            # Get all enrollments in one query
            enrollment_ids = [item["enrollment_id"] for item in attendance_data]
            enrollments = {
                e.id: e
                for e in StudentEnrollment.objects.filter(
                    id__in=enrollment_ids,
                    academic_class=session.academic_class,
                    is_active=True,
                ).select_related("student")
            }

            # Validate all enrollments exist
            missing_ids = set(enrollment_ids) - set(enrollments.keys())
            if missing_ids:
                return Response(
                    {
                        "success": False,
                        "message": f"Invalid enrollment IDs: {missing_ids}",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Bulk create/update attendance
            with transaction.atomic():
                attendance_records = []
                for data in attendance_data:
                    enrollment = enrollments[data["enrollment_id"]]

                    attendance, _ = StudentAttendance.objects.update_or_create(
                        session=session,
                        enrollment=enrollment,
                        defaults={
                            "student": enrollment.student,
                            "status": data["status"],
                            "remarks": data.get("remarks", ""),
                            "late_minutes": data.get("late_minutes"),
                            "marked_by": teacher,
                        },
                    )
                    attendance_records.append(attendance)

                # Session counts updated via signal

                logger.info(
                    f"Bulk attendance marked: {len(attendance_records)} records for session {session.id}"
                )

            return Response(
                {
                    "success": True,
                    "message": f"Successfully marked {len(attendance_records)} attendance records",
                    "data": {
                        "marked_count": len(attendance_records),
                        "session": AttendanceSessionSerializer(session).data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in BulkMarkAttendanceView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class SubmitAttendanceView(APIView):
    """
    POST /teacher/attendance/session/<session_id>/submit/

    Submit/finalize the attendance session.
    Once submitted, status changes to SUBMITTED.
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, session_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            session = AttendanceSession.objects.filter(
                id=session_id, taken_by=teacher, is_active=True
            ).first()

            if not session:
                return Response(
                    {"success": False, "message": "Attendance session not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            if session.status != "OPEN":
                return Response(
                    {"success": False, "message": f"Session already {session.status}"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Check if all students are marked
            marked_count = StudentAttendance.objects.filter(
                session=session, is_active=True
            ).count()

            if marked_count < session.total_students:
                return Response(
                    {
                        "success": False,
                        "message": f"Cannot submit: {session.total_students - marked_count} students pending",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Update session status
            session.status = "SUBMITTED"
            session.save(update_fields=["status", "updated_at"])

            logger.info(f"Attendance session submitted: {session.id}")

            return Response(
                {
                    "success": True,
                    "message": "Attendance submitted successfully",
                    "data": AttendanceSessionSerializer(session).data,
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in SubmitAttendanceView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class AttendanceHistoryView(APIView):
    """
    GET /teacher/attendance/history/

    Get attendance history with filters:
    - from_date, to_date
    - class_id
    - status (OPEN, SUBMITTED, LOCKED)
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get filter parameters
            from_date = request.query_params.get("from_date")
            to_date = request.query_params.get("to_date")
            class_id = request.query_params.get("class_id")
            status_filter = request.query_params.get("status")

            # Base queryset
            sessions = (
                AttendanceSession.objects.filter(taken_by=teacher, is_active=True)
                .select_related("academic_class__standard", "academic_class__section")
                .order_by("-date", "-created_at")
            )

            # Apply filters
            if from_date:
                sessions = sessions.filter(date__gte=from_date)
            if to_date:
                sessions = sessions.filter(date__lte=to_date)
            if class_id:
                sessions = sessions.filter(academic_class_id=class_id)
            if status_filter:
                sessions = sessions.filter(status=status_filter)

            # Pagination
            page = int(request.query_params.get("page", 1))
            page_size = int(request.query_params.get("page_size", 20))
            start = (page - 1) * page_size
            end = start + page_size

            total_count = sessions.count()
            paginated_sessions = sessions[start:end]

            # Calculate summary statistics
            summary = sessions.aggregate(
                total_sessions=Count("id"),
                total_students_marked=Sum("total_students"),
                avg_attendance=Avg(
                    (models.F("present_count") + models.F("late_count"))
                    * 100.0
                    / models.F("total_students"),
                    output_field=models.FloatField(),
                ),
            )

            return Response(
                {
                    "success": True,
                    "data": {
                        "sessions": AttendanceHistorySerializer(
                            paginated_sessions, many=True
                        ).data,
                        "pagination": {
                            "page": page,
                            "page_size": page_size,
                            "total_count": total_count,
                            "total_pages": (total_count + page_size - 1) // page_size,
                        },
                        "summary": {
                            "total_sessions": summary["total_sessions"] or 0,
                            "total_students_marked": summary["total_students_marked"]
                            or 0,
                            "average_attendance": round(
                                summary["avg_attendance"] or 0, 2
                            ),
                        },
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in AttendanceHistoryView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class AttendanceSummaryView(APIView):
    """
    GET /teacher/attendance/summary/

    Get monthly attendance summary for class teacher's class.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            today = timezone.now().date()

            # Get current academic year
            academic_year = get_request_academic_year(self.request)

            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get class where teacher is class teacher
            academic_class = AcademicClass.objects.filter(
                class_teacher=teacher, academic_year=academic_year, is_active=True
            ).first()

            if not academic_class:
                return Response(
                    {
                        "success": False,
                        "message": "You are not a class teacher for any active class",
                    },
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get month/year from query params or use current
            month = int(request.query_params.get("month", today.month))
            year = int(request.query_params.get("year", today.year))

            # Get summaries for this class
            summaries = (
                AttendanceSummary.objects.filter(
                    academic_class=academic_class, month=month, year=year
                )
                .select_related("student", "enrollment")
                .order_by("enrollment__roll_number")
            )

            # Calculate class statistics
            total_students = summaries.count()
            if total_students > 0:
                class_avg = summaries.aggregate(
                    avg_present=Avg("present_days"),
                    avg_absent=Avg("absent_days"),
                    avg_attendance=Avg("attendance_percentage"),
                    below_minimum=Count("id", filter=Q(is_below_minimum=True)),
                )
            else:
                class_avg = {
                    "avg_present": 0,
                    "avg_absent": 0,
                    "avg_attendance": 0,
                    "below_minimum": 0,
                }

            return Response(
                {
                    "success": True,
                    "data": {
                        "class_info": {
                            "id": academic_class.id,
                            "name": str(academic_class),
                        },
                        "month": month,
                        "year": year,
                        "total_students": total_students,
                        "class_statistics": {
                            "average_present_days": round(
                                class_avg["avg_present"] or 0, 2
                            ),
                            "average_absent_days": round(
                                class_avg["avg_absent"] or 0, 2
                            ),
                            "average_attendance_percentage": round(
                                class_avg["avg_attendance"] or 0, 2
                            ),
                            "students_below_minimum": class_avg["below_minimum"],
                        },
                        "student_summaries": AttendanceSummarySerializer(
                            summaries, many=True
                        ).data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in AttendanceSummaryView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class AttendanceReportsView(APIView):
    """
    GET /teacher/attendance/reports/

    Generate attendance reports with various filters.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            today = timezone.now().date()

            filter_serializer = AttendanceReportFilterSerializer(
                data=request.query_params
            )
            if not filter_serializer.is_valid():
                return Response(
                    {"success": False, "errors": filter_serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            filters = filter_serializer.validated_data

            # Get class where teacher is class teacher
            academic_year = get_request_academic_year(self.request)

            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            academic_class = AcademicClass.objects.filter(
                class_teacher=teacher, academic_year=academic_year, is_active=True
            ).first()

            if not academic_class and not filters.get("class_id"):
                return Response(
                    {
                        "success": False,
                        "message": "You are not a class teacher for any active class. Please specify class_id.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Use specified class or teacher's class
            class_id = filters.get(
                "class_id", academic_class.id if academic_class else None
            )

            if not class_id:
                return Response(
                    {"success": False, "message": "No class specified"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Build base queryset
            summaries = AttendanceSummary.objects.filter(
                academic_class_id=class_id
            ).select_related("student", "enrollment")

            # Apply filters
            if filters.get("month"):
                summaries = summaries.filter(month=filters["month"])
            if filters.get("year"):
                summaries = summaries.filter(year=filters["year"])
            if filters.get("student_id"):
                summaries = summaries.filter(student_id=filters["student_id"])
            if filters.get("below_minimum"):
                summaries = summaries.filter(is_below_minimum=True)

            # Calculate report data
            report_data = []
            for summary in summaries:
                report_data.append(
                    {
                        "student_id": summary.student.id,
                        "student_name": str(summary.student),
                        "roll_number": summary.enrollment.roll_number,
                        "month": summary.month,
                        "year": summary.year,
                        "total_working_days": summary.total_working_days,
                        "present": summary.present_days,
                        "absent": summary.absent_days,
                        "late": summary.late_days,
                        "leave": summary.leave_days,
                        "half_days": summary.half_days,
                        "attendance_percentage": float(summary.attendance_percentage),
                        "is_below_minimum": summary.is_below_minimum,
                        "effective_present": summary.present_days
                        + summary.late_days
                        + (summary.half_days * 0.5),
                    }
                )

            # Calculate overall statistics
            if report_data:
                total_students = len(report_data)
                avg_attendance = (
                    sum(d["attendance_percentage"] for d in report_data)
                    / total_students
                )
                below_minimum = sum(1 for d in report_data if d["is_below_minimum"])
            else:
                total_students = 0
                avg_attendance = 0
                below_minimum = 0

            return Response(
                {
                    "success": True,
                    "data": {
                        "report_parameters": {
                            "class_id": class_id,
                            "month": filters.get("month", "All"),
                            "year": filters.get("year", "All"),
                        },
                        "summary_statistics": {
                            "total_students": total_students,
                            "average_attendance": round(avg_attendance, 2),
                            "students_below_minimum": below_minimum,
                            "percentage_below_minimum": round(
                                (
                                    (below_minimum / total_students * 100)
                                    if total_students > 0
                                    else 0
                                ),
                                2,
                            ),
                        },
                        "report_data": report_data,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in AttendanceReportsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


# =====================================================
# TEACHER CHAT VIEWS
# =====================================================
class TeacherClassesForChatView(APIView):
    """
    GET /teacher/chat/classes/

    Get all classes where teacher is either:
    - Class teacher
    - Teaching a subject
    Returns classes with subject info for group creation
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Chat group creation is a "now" action — always use the true
            # current academic year, ignoring any "view as year X" override
            # the client may have pinned (that's for browsing historical
            # records, not for who a teacher currently teaches).
            academic_year = get_current_academic_year()

            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get classes where teacher is class teacher
            class_teacher_classes = AcademicClass.objects.filter(
                class_teacher=teacher, academic_year=academic_year, is_active=True
            ).select_related("standard", "section")

            # Get classes where teacher teaches a subject
            subject_teacher_classes = AcademicClass.objects.filter(
                subject_teachers__teacher=teacher,
                subject_teachers__is_active=True,
                academic_year=academic_year,
                is_active=True,
            ).select_related("standard", "section")

            # ✅ FIX: Combine using union instead of | operator
            # Or use Q objects with distinct()
            all_classes = (class_teacher_classes | subject_teacher_classes).distinct()

            classes_data = []
            for academic_class in all_classes:
                # Get subjects teacher teaches in this class
                subjects = SubjectTeacher.objects.filter(
                    teacher=teacher, academic_class=academic_class, is_active=True
                ).select_related("subject")

                # Check if class group already exists
                existing_class_group = ChatRoom.objects.filter(
                    room_type="CLASS",
                    academic_class=academic_class,
                    academic_year=academic_year,
                    is_active=True,
                ).first()

                # Get existing subject groups
                subject_groups = []
                for subject_teacher in subjects:
                    existing_subject_group = ChatRoom.objects.filter(
                        room_type="SUBJECT",
                        academic_class=academic_class,
                        subject=subject_teacher.subject,
                        academic_year=academic_year,
                        is_active=True,
                    ).first()

                    subject_groups.append(
                        {
                            "subject_id": subject_teacher.subject.id,
                            "subject_name": subject_teacher.subject.name,
                            "subject_code": subject_teacher.subject.code,
                            "existing_group_id": (
                                str(existing_subject_group.id)
                                if existing_subject_group
                                else None
                            ),
                            "has_group": existing_subject_group is not None,
                        }
                    )

                classes_data.append(
                    {
                        "class_id": academic_class.id,
                        "class_name": f"{academic_class.standard.name} - {academic_class.section.name}",
                        "standard": academic_class.standard.name,
                        "section": academic_class.section.name,
                        "total_students": academic_class.enrollments.filter(
                            is_active=True
                        ).count(),
                        "is_class_teacher": academic_class.class_teacher_id
                        == teacher.id,
                        "subjects": subject_groups,
                        "existing_class_group": {
                            "room_id": (
                                str(existing_class_group.id)
                                if existing_class_group
                                else None
                            ),
                            "has_group": existing_class_group is not None,
                            "room_name": (
                                existing_class_group.name
                                if existing_class_group
                                else None
                            ),
                        },
                    }
                )

            return Response(
                {
                    "success": True,
                    "data": {
                        "classes": classes_data,
                        "total_classes": len(classes_data),
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherClassesForChatView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

class TeacherCreateClassGroupView(APIView):
    """
    POST /teacher/chat/create-class-group/

    Create or get existing class group for a class
    All students in the class and the teacher will be added
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            class_id = request.data.get("class_id")
            group_name = request.data.get("group_name", None)

            if not class_id:
                return Response(
                    {"success": False, "message": "class_id is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Get the academic class
            academic_class = (
                AcademicClass.objects.filter(id=class_id, is_active=True)
                .select_related("standard", "section", "academic_year")
                .first()
            )

            if not academic_class:
                return Response(
                    {"success": False, "message": "Class not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Reject stale class_ids from a previous academic year (e.g. a
            # cached class list, or a client still pinned to a past "browsing
            # year") — chat groups must be created against the true current
            # year's class, not a promoted-from class.
            current_academic_year = get_current_academic_year()
            if (
                current_academic_year
                and academic_class.academic_year_id != current_academic_year.id
            ):
                return Response(
                    {
                        "success": False,
                        "message": "This class belongs to a previous academic year. Please refresh your class list and try again.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Verify teacher has access to this class
            has_access = (
                academic_class.class_teacher_id == teacher.id
                or SubjectTeacher.objects.filter(
                    teacher=teacher, academic_class=academic_class, is_active=True
                ).exists()
            )

            if not has_access:
                return Response(
                    {
                        "success": False,
                        "message": "You don't have access to this class",
                    },
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Check if group already exists
            existing_room = ChatRoom.objects.filter(
                room_type="CLASS",
                academic_class=academic_class,
                academic_year=academic_class.academic_year,
                is_active=True,
            ).first()

            if existing_room:
                # Check if teacher is already a participant, if not add them
                teacher_participant = ChatParticipantTeacher.objects.filter(
                    room=existing_room, teacher=teacher, is_active=True
                ).first()
                
                if not teacher_participant:
                    # Add teacher as participant (ADMIN role)
                    ChatParticipantTeacher.objects.create(
                        room=existing_room,
                        teacher=teacher,
                        role="ADMIN",
                        is_active=True
                    )
                    # Also add to many-to-many for backward compatibility
                    existing_room.teachers.add(teacher)
                
                serializer = ChatRoomSerializer(
                    existing_room,
                    context={
                        "request": request,
                        "user_type": "teacher",
                        "user_id": str(teacher.id),
                    },
                )
                return Response(
                    {
                        "success": True,
                        "message": "Class group already exists",
                        "is_new": False,
                        "data": serializer.data,
                    }
                )

            # Create new class group
            room_name = group_name or f"{academic_class} - Class Group"

            room = ChatRoom.objects.create(
                room_type="CLASS",
                name=room_name,
                description=f"Official class group for {academic_class}",
                academic_class=academic_class,
                academic_year=academic_class.academic_year,
                created_by_type="teacher",
                created_by_id=str(teacher.id),
                is_active=True,
                is_encrypted=True,
                admins=[{"type": "teacher", "id": str(teacher.id)}],  # Add to admins JSON field
            )

            # Add teacher as participant (ADMIN role) - ONLY create through model, NOT using teachers.add()
            teacher_participant = ChatParticipantTeacher.objects.create(
                room=room,
                teacher=teacher,
                role="ADMIN",
                is_active=True,
            )
            
            # Also add to the many-to-many relation (this will create another through record if not careful)
            # To avoid duplication, we should NOT use room.teachers.add() since we already created the through record
            # Instead, we'll add directly to the teachers many-to-many by using add with through_defaults
            # But to keep it simple, we'll just rely on the ChatParticipantTeacher record
            # The teachers many-to-many is just for convenience, we'll add the teacher there too
            # But we need to use the through model's default values
            room.teachers.add(teacher)

            # Add all students in the class
            enrollments = StudentEnrollment.objects.filter(
                academic_class=academic_class, is_active=True
            ).select_related("student")

            students_added = 0
            students_skipped = 0

            for enrollment in enrollments:
                # Create participant record (this will also handle the many-to-many through the model)
                student_participant, created = ChatParticipantStudent.objects.get_or_create(
                    room=room,
                    student=enrollment.student,
                    defaults={
                        "role": "MEMBER", 
                        "is_active": True,
                        "notification_enabled": True,
                    },
                )

                if created:
                    students_added += 1
                    # Also add to the many-to-many for convenience
                    room.students.add(enrollment.student)
                else:
                    students_skipped += 1

            logger.info(
                f"Class group created: {room.id} for {academic_class} by teacher {teacher.id}. "
                f"Students added: {students_added}, skipped: {students_skipped}"
            )
            log_teacher_activity(
                teacher=teacher,
                action='CREATE_CLASS_GROUP',
                description=f'Created class group "{room_name}" for {academic_class}',
                metadata={'room_id': str(room.id), 'class_id': class_id, 'students_added': students_added},
            )

            serializer = ChatRoomSerializer(
                room,
                context={
                    "request": request,
                    "user_type": "teacher",
                    "user_id": str(teacher.id),
                },
            )

            return Response(
                {
                    "success": True,
                    "message": f"Class group created successfully. Added {students_added} students (skipped {students_skipped} existing)",
                    "is_new": True,
                    "data": serializer.data,
                },
                status=status.HTTP_201_CREATED,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherCreateClassGroupView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
            
class TeacherCreateSubjectGroupView(APIView):
    """
    POST /teacher/chat/create-subject-group/

    Create or get existing subject group for a specific subject in a class
    Only students who have selected this subject will be added
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            class_id = request.data.get("class_id")
            subject_id = request.data.get("subject_id")
            group_name = request.data.get("group_name", None)

            if not class_id or not subject_id:
                return Response(
                    {
                        "success": False,
                        "message": "class_id and subject_id are required",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Get the academic class and subject
            academic_class = (
                AcademicClass.objects.filter(id=class_id, is_active=True)
                .select_related("standard", "section", "academic_year")
                .first()
            )

            if not academic_class:
                return Response(
                    {"success": False, "message": "Class not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Reject stale class_ids from a previous academic year (e.g. a
            # cached class list, or a client still pinned to a past "browsing
            # year") — chat groups must be created against the true current
            # year's class, not a promoted-from class.
            current_academic_year = get_current_academic_year()
            if (
                current_academic_year
                and academic_class.academic_year_id != current_academic_year.id
            ):
                return Response(
                    {
                        "success": False,
                        "message": "This class belongs to a previous academic year. Please refresh your class list and try again.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            subject = Subject.objects.filter(id=subject_id, is_active=True).first()

            if not subject:
                return Response(
                    {"success": False, "message": "Subject not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Verify teacher teaches this subject in this class
            subject_teacher = SubjectTeacher.objects.filter(
                teacher=teacher,
                academic_class=academic_class,
                subject=subject,
                is_active=True,
            ).first()

            if not subject_teacher:
                return Response(
                    {
                        "success": False,
                        "message": "You don't teach this subject in this class",
                    },
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Check if group already exists
            existing_room = ChatRoom.objects.filter(
                room_type="SUBJECT",
                academic_class=academic_class,
                subject=subject,
                academic_year=academic_class.academic_year,
                is_active=True,
            ).first()

            if existing_room:
                # Check if teacher is already a participant
                teacher_participant = ChatParticipantTeacher.objects.filter(
                    room=existing_room, teacher=teacher, is_active=True
                ).first()
                
                if not teacher_participant:
                    # Add teacher as participant (ADMIN role)
                    ChatParticipantTeacher.objects.create(
                        room=existing_room,
                        teacher=teacher,
                        role="ADMIN",
                        is_active=True
                    )
                    existing_room.teachers.add(teacher)
                    
                    # Update admins JSON field
                    admins = existing_room.admins or []
                    admin_entry = {"type": "teacher", "id": str(teacher.id)}
                    if admin_entry not in admins:
                        admins.append(admin_entry)
                        existing_room.admins = admins
                        existing_room.save(update_fields=['admins'])
                elif teacher_participant.role != "ADMIN":
                    # Upgrade to admin if not already
                    teacher_participant.role = "ADMIN"
                    teacher_participant.save(update_fields=['role'])
                
                serializer = ChatRoomSerializer(
                    existing_room,
                    context={
                        "request": request,
                        "user_type": "teacher",
                        "user_id": str(teacher.id),
                    },
                )
                return Response(
                    {
                        "success": True,
                        "message": "Subject group already exists",
                        "is_new": False,
                        "data": serializer.data,
                    }
                )

            # Create new subject group
            room_name = group_name or f"{subject.name} - {academic_class}"

            room = ChatRoom.objects.create(
                room_type="SUBJECT",
                name=room_name,
                description=f"Subject group for {subject.name} - {academic_class}",
                academic_class=academic_class,
                subject=subject,
                academic_year=academic_class.academic_year,
                created_by_type="teacher",
                created_by_id=str(teacher.id),
                is_active=True,
                is_encrypted=True,
                admins=[{"type": "teacher", "id": str(teacher.id)}],  # Add to admins JSON field
            )

            # Add teacher as participant (ADMIN role)
            teacher_participant = ChatParticipantTeacher.objects.create(
                room=room,
                teacher=teacher,
                role="ADMIN",
                is_active=True,
            )
            room.teachers.add(teacher)

            # Add students who have selected this subject
            students_added = 0
            students_skipped = 0

            if academic_class.standard.standard_type == "higher_secondary":
                # Students with this subject group
                enrollments = (
                    StudentEnrollment.objects.filter(
                        academic_class=academic_class, is_active=True
                    )
                    .filter(
                        Q(subject_groups__subject_group__subjects=subject)
                        | Q(selected_subjects__subject=subject)
                    )
                    .distinct()
                    .select_related("student")
                )
            else:
                # All students take this subject
                enrollments = StudentEnrollment.objects.filter(
                    academic_class=academic_class, is_active=True
                ).select_related("student")

            for enrollment in enrollments:
                # Create or get student participant
                student_participant, created = ChatParticipantStudent.objects.get_or_create(
                    room=room,
                    student=enrollment.student,
                    defaults={
                        "role": "MEMBER",
                        "is_active": True,
                        "notification_enabled": True,
                    },
                )
                
                if created:
                    students_added += 1
                    # Add to many-to-many
                    room.students.add(enrollment.student)
                else:
                    students_skipped += 1

            logger.info(
                f"Subject group created: {room.id} for {subject.name} in {academic_class} by teacher {teacher.id}. "
                f"Students added: {students_added}, skipped: {students_skipped}"
            )

            serializer = ChatRoomSerializer(
                room,
                context={
                    "request": request,
                    "user_type": "teacher",
                    "user_id": str(teacher.id),
                },
            )

            return Response(
                {
                    "success": True,
                    "message": f"Subject group created successfully. Added {students_added} students (skipped {students_skipped} existing)",
                    "is_new": True,
                    "data": serializer.data,
                },
                status=status.HTTP_201_CREATED,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherCreateSubjectGroupView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )           


class TeacherClassStudentsForChatView(APIView):
    """
    GET /teacher/chat/class-students/?class_id=<id>   (class_id optional — omit for all classes)

    Returns students in teacher's classes with their parent details.
    Used by the Direct Message flow so teacher can pick student or parent to chat with.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            from people.models import Student, Parent, StudentParent

            teacher = Teacher.objects.get(external_user_id=request.user.id)
            class_id = request.query_params.get("class_id")

            # Picking who to message is a "now" action — always use the true
            # current academic year, ignoring any pinned "browsing year".
            academic_year = get_current_academic_year()
            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            class_teacher_qs = AcademicClass.objects.filter(
                class_teacher=teacher, academic_year=academic_year, is_active=True
            )
            subject_teacher_qs = AcademicClass.objects.filter(
                subject_teachers__teacher=teacher,
                subject_teachers__is_active=True,
                academic_year=academic_year,
                is_active=True,
            )
            all_classes = (class_teacher_qs | subject_teacher_qs).distinct().select_related(
                "standard", "section"
            )

            if class_id:
                all_classes = all_classes.filter(id=class_id)
                if not all_classes.exists():
                    return Response(
                        {"success": False, "message": "Class not found or access denied"},
                        status=status.HTTP_403_FORBIDDEN,
                    )

            result = []
            for ac in all_classes:
                enrollments = StudentEnrollment.objects.filter(
                    academic_class=ac, is_active=True
                ).select_related("student")

                students_data = []
                for enrollment in enrollments:
                    student = enrollment.student
                    student_parents = StudentParent.objects.filter(
                        student=student, is_active=True
                    ).select_related("parent")

                    parents_data = []
                    for sp in student_parents:
                        p = sp.parent
                        parents_data.append({
                            "id": p.id,
                            "name": p.full_name,
                            "phone": p.phone,
                            "profile_image": p.profile_image.url if p.profile_image else None,
                            "relationship": sp.relationship,
                            "is_primary": sp.is_primary_contact,
                        })

                    students_data.append({
                        "id": student.id,
                        "full_name": student.full_name,
                        "roll_number": student.roll_number,
                        "profile_image": student.profile_image.url if student.profile_image else None,
                        "parents": parents_data,
                    })

                result.append({
                    "class_id": ac.id,
                    "class_name": str(ac),
                    "standard": ac.standard.name if ac.standard else None,
                    "section": ac.section.name if ac.section else None,
                    "total_students": len(students_data),
                    "students": students_data,
                })

            return Response({"success": True, "data": result}, status=status.HTTP_200_OK)

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherClassStudentsForChatView: {e}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherCreateDirectChatView(APIView):
    """
    POST /teacher/chat/create-direct/

    Create (or return existing) 1-to-1 chat room between the teacher and a student or parent.
    Body: { target_type: "student"|"parent", target_id: <int> }
    """

    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            from people.models import Student, Parent

            teacher = Teacher.objects.get(external_user_id=request.user.id)
            target_type = request.data.get("target_type")
            target_id = request.data.get("target_id")

            if not target_type or not target_id:
                return Response(
                    {"success": False, "message": "target_type and target_id are required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )
            if target_type not in ("student", "parent"):
                return Response(
                    {"success": False, "message": "target_type must be 'student' or 'parent'"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if target_type == "student":
                try:
                    student = Student.objects.get(id=target_id)
                except Student.DoesNotExist:
                    return Response(
                        {"success": False, "message": "Student not found"},
                        status=status.HTTP_404_NOT_FOUND,
                    )

                existing = ChatRoom.objects.filter(
                    teachers=teacher,
                    students=student,
                    room_type="INDIVIDUAL",
                    is_active=True,
                ).first()

                if existing:
                    return Response(
                        {"success": True, "room_id": str(existing.id), "room_name": existing.name, "created": False},
                        status=status.HTTP_200_OK,
                    )

                room = ChatRoom.objects.create(
                    room_type="INDIVIDUAL",
                    name=f"{teacher.full_name} & {student.full_name}",
                    is_active=True,
                    created_by_type="teacher",
                    created_by_id=str(teacher.id),
                )
                ChatParticipantTeacher.objects.create(room=room, teacher=teacher, role="ADMIN", is_active=True)
                room.teachers.add(teacher)
                ChatParticipantStudent.objects.create(room=room, student=student, role="MEMBER", is_active=True)
                room.students.add(student)

            else:  # parent
                try:
                    parent = Parent.objects.get(id=target_id)
                except Parent.DoesNotExist:
                    return Response(
                        {"success": False, "message": "Parent not found"},
                        status=status.HTTP_404_NOT_FOUND,
                    )

                existing = ChatRoom.objects.filter(
                    teachers=teacher,
                    parents=parent,
                    room_type="INDIVIDUAL",
                    is_active=True,
                ).first()

                if existing:
                    return Response(
                        {"success": True, "room_id": str(existing.id), "room_name": existing.name, "created": False},
                        status=status.HTTP_200_OK,
                    )

                room = ChatRoom.objects.create(
                    room_type="INDIVIDUAL",
                    name=f"{teacher.full_name} & {parent.full_name}",
                    is_active=True,
                    created_by_type="teacher",
                    created_by_id=str(teacher.id),
                )
                ChatParticipantTeacher.objects.create(room=room, teacher=teacher, role="ADMIN", is_active=True)
                room.teachers.add(teacher)
                ChatParticipantParent.objects.create(room=room, parent=parent, role="MEMBER", is_active=True)
                room.parents.add(parent)

            return Response(
                {"success": True, "room_id": str(room.id), "room_name": room.name, "created": True},
                status=status.HTTP_201_CREATED,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherCreateDirectChatView: {e}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherChatRoomListView(APIView):
    """
    GET /teacher/chat/rooms/

    Get all chat rooms where teacher is a participant
    Returns class groups, subject groups, and individual chats
    
    Query Parameters:
    - filter: 'all', 'class_groups', 'subject_groups', 'individual_chats' (default: 'all')
    - page: int (default: 1)
    - page_size: int (default: 20)
    - search: string (optional) - search by room name or participant name
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get filter and pagination parameters
            filter_type = request.query_params.get('filter', 'all')
            page = int(request.query_params.get('page', 1))
            page_size = int(request.query_params.get('page_size', 20))
            search_query = request.query_params.get('search', '')
            
            # Calculate offset
            offset = (page - 1) * page_size
            
            # Get all rooms where teacher is participant
            rooms_qs = ChatRoom.objects.filter(teachers=teacher, is_active=True).select_related(
                "academic_class__standard",
                "academic_class__section",
                "subject",
                "academic_year",
            ).prefetch_related(
                "teachers", 
                "parents", 
                "students",
                "messages"
            )
            
            # Apply search filter
            if search_query:
                rooms_qs = rooms_qs.filter(
                    Q(name__icontains=search_query) |
                    Q(academic_class__standard__name__icontains=search_query) |
                    Q(academic_class__section__name__icontains=search_query) |
                    Q(subject__name__icontains=search_query)
                )
            
            # Separate rooms by type based on filter
            if filter_type == 'class_groups':
                rooms_qs = rooms_qs.filter(room_type="CLASS")
            elif filter_type == 'subject_groups':
                rooms_qs = rooms_qs.filter(room_type="SUBJECT")
            elif filter_type == 'individual_chats':
                rooms_qs = rooms_qs.filter(room_type="INDIVIDUAL")
            # 'all' - no filter
            
            # Rooms with messages: ordered by most recent message. New rooms (no messages): float to top.
            rooms_qs = rooms_qs.order_by(F('last_message_at').desc(nulls_first=True), '-created_at')
            
            # Get total count for pagination
            total_count = rooms_qs.count()
            
            # Apply pagination
            paginated_rooms = rooms_qs[offset:offset + page_size]
            
            # Get all subjects this teacher teaches (to determine which class/student they are associated with)
            teacher_subjects = SubjectTeacher.objects.filter(
                teacher=teacher,
                is_active=True
            ).select_related('academic_class', 'subject')
            
            # Create a set of class IDs this teacher teaches
            teacher_class_ids = set(ts.academic_class_id for ts in teacher_subjects)
            
            # Build response data
            class_groups = []
            subject_groups = []
            individual_chats = []
            
            for room in paginated_rooms:
                # Get unread count for teacher
                unread_count = self._get_unread_count(teacher, room)
                
                # Get last message
                last_message = room.messages.filter(is_deleted=False).order_by("-created_at").first()
                
                room_data = {
                    "room_id": str(room.id),
                    "room_type": room.room_type,
                    "name": room.name,
                    "description": room.description,
                    "created_at": room.created_at,
                    "last_message_at": room.last_message_at,
                    "unread_count": unread_count,
                    "total_participants": room.students.count() + room.teachers.count() + room.parents.count(),
                    "last_message": (
                        {
                            "id": str(last_message.id),
                            "content": last_message.content[:100] if last_message and last_message.content else None,
                            "message_type": last_message.message_type,
                            "sender_type": last_message.sender_type,
                            "sender_name": last_message.get_sender_name(),
                            "created_at": last_message.created_at,
                            "file_url": last_message.file.url if last_message and last_message.file else None,
                        }
                        if last_message
                        else None
                    ),
                }
                
                if room.room_type == "CLASS":
                    room_data["class_info"] = {
                        "class_id": room.academic_class.id if room.academic_class else None,
                        "class_name": str(room.academic_class) if room.academic_class else None,
                        "standard": room.academic_class.standard.name if room.academic_class and room.academic_class.standard else None,
                        "section": room.academic_class.section.name if room.academic_class and room.academic_class.section else None,
                        "total_students": room.students.count(),
                    }
                    class_groups.append(room_data)
                
                elif room.room_type == "SUBJECT":
                    room_data["subject_info"] = {
                        "subject_id": room.subject.id if room.subject else None,
                        "subject_name": room.subject.name if room.subject else None,
                        "subject_code": room.subject.code if room.subject else None,
                        "class_id": room.academic_class.id if room.academic_class else None,
                        "class_name": str(room.academic_class) if room.academic_class else None,
                    }
                    subject_groups.append(room_data)
                
                else:
                    # Individual chats with parents or students
                    other_participant = None
                    
                    if room.parents.exists():
                        parent_obj = room.parents.first()
                        
                        # Get child info for this parent
                        # Find which student of this parent is in a class that this teacher teaches
                        child_info = None
                        
                        # Get all children of this parent
                        student_parents = parent_obj.student_parents.filter(
                            is_active=True
                        ).select_related('student')
                        
                        for sp in student_parents:
                            student = sp.student
                            
                            # Get current enrollment for this student (most recent year first —
                            # a student can have multiple is_active=True rows across years)
                            enrollment = StudentEnrollment.objects.filter(
                                student=student,
                                is_active=True
                            ).select_related('academic_class__standard', 'academic_class__section').order_by(
                                '-academic_class__academic_year__start_date'
                            ).first()

                            if enrollment and enrollment.academic_class_id in teacher_class_ids:
                                # This student is in a class that this teacher teaches
                                child_info = {
                                    "student_id": student.id,
                                    "student_name": student.full_name,
                                    "class_id": enrollment.academic_class.id,
                                    "class_name": str(enrollment.academic_class),
                                    "standard": enrollment.academic_class.standard.name if enrollment.academic_class.standard else None,
                                    "section": enrollment.academic_class.section.name if enrollment.academic_class.section else None,
                                    "roll_number": enrollment.roll_number,
                                    "relationship": sp.relationship,
                                }
                                break  # Found the relevant child
                        
                        # If no child found in teacher's classes, get the first child
                        if not child_info and student_parents.exists():
                            first_sp = student_parents.first()
                            student = first_sp.student
                            enrollment = StudentEnrollment.objects.filter(
                                student=student,
                                is_active=True
                            ).select_related('academic_class__standard', 'academic_class__section').order_by(
                                '-academic_class__academic_year__start_date'
                            ).first()

                            if enrollment:
                                child_info = {
                                    "student_id": student.id,
                                    "student_name": student.full_name,
                                    "class_id": enrollment.academic_class.id,
                                    "class_name": str(enrollment.academic_class),
                                    "standard": enrollment.academic_class.standard.name if enrollment.academic_class.standard else None,
                                    "section": enrollment.academic_class.section.name if enrollment.academic_class.section else None,
                                    "roll_number": enrollment.roll_number,
                                    "relationship": first_sp.relationship,
                                }
                        
                        other_participant = {
                            "type": "parent",
                            "id": parent_obj.id,
                            "name": parent_obj.full_name,
                            "profile_image": parent_obj.profile_image.url if parent_obj.profile_image else None,
                            "child_info": child_info,
                        }
                    
                    elif room.students.exists():
                        student_obj = room.students.first()
                        
                        # Get enrollment for this student (most recent year first)
                        enrollment = StudentEnrollment.objects.filter(
                            student=student_obj,
                            is_active=True
                        ).select_related('academic_class__standard', 'academic_class__section').order_by(
                            '-academic_class__academic_year__start_date'
                        ).first()

                        other_participant = {
                            "type": "student",
                            "id": student_obj.id,
                            "name": student_obj.full_name,
                            "roll_number": student_obj.roll_number,
                            "profile_image": student_obj.profile_image.url if student_obj.profile_image else None,
                            "class_name": str(enrollment.academic_class) if enrollment and enrollment.academic_class else None,
                            "class_id": enrollment.academic_class.id if enrollment and enrollment.academic_class else None,
                        }
                    
                    room_data["other_participant"] = other_participant
                    individual_chats.append(room_data)
            
            # Prepare response based on filter
            if filter_type == 'class_groups':
                response_data = {
                    "rooms": class_groups,
                    "total_count": total_count,
                }
            elif filter_type == 'subject_groups':
                response_data = {
                    "rooms": subject_groups,
                    "total_count": total_count,
                }
            elif filter_type == 'individual_chats':
                response_data = {
                    "rooms": individual_chats,
                    "total_count": total_count,
                }
            else:
                response_data = {
                    "class_groups": class_groups,
                    "subject_groups": subject_groups,
                    "individual_chats": individual_chats,
                    "total_count": total_count,
                }
            
            # Add counts summary
            total_class_groups = ChatRoom.objects.filter(teachers=teacher, room_type="CLASS", is_active=True).count()
            total_subject_groups = ChatRoom.objects.filter(teachers=teacher, room_type="SUBJECT", is_active=True).count()
            total_individual_chats = ChatRoom.objects.filter(teachers=teacher, room_type="INDIVIDUAL", is_active=True).count()
            
            # Calculate pagination metadata
            total_pages = (total_count + page_size - 1) // page_size if page_size > 0 else 0
            has_next = offset + page_size < total_count
            has_previous = page > 1
            
            return Response(
                {
                    "success": True,
                    "data": response_data,
                    "summary": {
                        "total_rooms": total_count,
                        "class_groups_count": total_class_groups,
                        "subject_groups_count": total_subject_groups,
                        "individual_chats_count": total_individual_chats,
                    },
                    "pagination": {
                        "current_page": page,
                        "page_size": page_size,
                        "total_pages": total_pages,
                        "total_items": total_count,
                        "has_next": has_next,
                        "has_previous": has_previous,
                        "next_page": page + 1 if has_next else None,
                        "previous_page": page - 1 if has_previous else None,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherChatRoomListView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _get_unread_count(self, teacher, room):
        """Get unread messages count for teacher in this room"""
        try:
            # Get all non-deleted messages in the room
            messages = Message.objects.filter(room=room, is_deleted=False)
            
            # Get message IDs that have been read by this teacher
            # Convert teacher.id to string since user_id in MessageReadReceipt is CharField
            read_receipts = MessageReadReceipt.objects.filter(
                user_type="teacher", 
                user_id=str(teacher.id)  # Ensure teacher.id is converted to string
            ).values_list("message_id", flat=True)
            
            # Count unread messages: 
            # 1. Not in read receipts
            # 2. Not sent by the teacher themselves
            unread_count = messages.exclude(id__in=read_receipts).exclude(
                sender_type="teacher", 
                sender_id=str(teacher.id)  # Also ensure sender_id is string for comparison
            ).count()
            
            return unread_count
            
        except Exception as e:
            # Log the error for debugging
            logger.error(f"Error calculating unread count for teacher {teacher.id} in room {room.id}: {str(e)}")
            return 0
        
        
class TeacherChatMessageListView(APIView):
    """
    GET /teacher/chat/rooms/<room_id>/messages/
    POST /teacher/chat/rooms/<room_id>/messages/

    Get messages for a chat room or send a new message
    When getting messages, automatically marks them as read
    Supports pagination with cursor-based loading (lazy loading)
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, room_id):
        """Get messages for a chat room with lazy loading pagination"""
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Verify teacher has access to this room
            if not ChatRoom.objects.filter(
                id=room_id, teachers=teacher, is_active=True
            ).exists():
                return Response(
                    {"success": False, "message": "Access denied"},
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Get pagination parameters
            page = int(request.query_params.get("page", 1))
            limit = int(request.query_params.get("limit", 10))  # 10 messages per page
            before_id = request.query_params.get("before_id")  # For cursor-based pagination
            after_id = request.query_params.get("after_id")    # For loading newer messages
            
            # Base queryset
            messages_qs = Message.objects.filter(
                room_id=room_id, 
                is_deleted=False
            ).select_related("room", "reply_to")
            
            # Cursor-based pagination (better for lazy loading)
            if before_id:
                # Load older messages (before this message ID)
                try:
                    before_message = Message.objects.get(id=before_id, room_id=room_id)
                    messages_qs = messages_qs.filter(
                        created_at__lt=before_message.created_at
                    )
                except Message.DoesNotExist:
                    pass
                    
            elif after_id:
                # Load newer messages (after this message ID)
                try:
                    after_message = Message.objects.get(id=after_id, room_id=room_id)
                    messages_qs = messages_qs.filter(
                        created_at__gt=after_message.created_at
                    )
                except Message.DoesNotExist:
                    pass
            
            # Get messages ordered by created_at (oldest to newest for display)
            messages = messages_qs.order_by("-created_at")[:limit]
            
            # Reverse to get chronological order (oldest first for display)
            messages = list(reversed(messages))
            
            # Get total count for pagination info
            total_messages = Message.objects.filter(
                room_id=room_id, is_deleted=False
            ).count()
            
            # Get cursor info for next/previous pages
            first_message_id = messages[0].id if messages else None
            last_message_id = messages[-1].id if messages else None
            
            # Check if more messages exist
            has_older = False
            if messages:
                has_older = Message.objects.filter(
                    room_id=room_id, 
                    is_deleted=False,
                    created_at__lt=messages[0].created_at
                ).exists()
            
            has_newer = False
            if messages:
                has_newer = Message.objects.filter(
                    room_id=room_id, 
                    is_deleted=False,
                    created_at__gt=messages[-1].created_at
                ).exists()
            
            # Mark messages as delivered AND read for teacher
            self._mark_as_delivered_and_read(room_id, teacher, messages)
            
            # Mark all messages in room as read (auto-read functionality)
            self._mark_all_as_read(room_id, teacher)

            serializer = MessageSerializer(
                messages,
                many=True,
                context={
                    "request": request,
                    "user_type": "teacher",
                    "user_id": str(teacher.id),
                },
            )

            return Response({
                "success": True,
                "data": {
                    "messages": serializer.data,
                    # So the client can tell its own typing/message events
                    # apart from the other participant's when both arrive
                    # over the socket.
                    "current_teacher_id": str(teacher.id),
                    "pagination": {
                        "total": total_messages,
                        "limit": limit,
                        "page": page,
                        "has_older": has_older,
                        "has_newer": has_newer,
                        "first_message_id": str(first_message_id) if first_message_id else None,
                        "last_message_id": str(last_message_id) if last_message_id else None,
                    }
                }
            })

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherChatMessageListView GET: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def post(self, request, room_id):
        """Send a new message"""
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Verify teacher has access to this room
            if not ChatRoom.objects.filter(
                id=room_id, teachers=teacher, is_active=True
            ).exists():
                return Response(
                    {"success": False, "message": "Access denied"},
                    status=status.HTTP_403_FORBIDDEN,
                )

            content = request.data.get("content")
            message_type = request.data.get("message_type", "TEXT")
            reply_to_id = request.data.get("reply_to_id")

            if not content:
                return Response(
                    {"success": False, "message": "Content is required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            message = Message.objects.create(
                room_id=room_id,
                sender_type="teacher",
                sender_id=str(teacher.id),
                content=content,
                message_type=message_type,
                reply_to_id=reply_to_id,
            )
            broadcast_new_message(message)

            ChatRoom.objects.filter(id=room_id).update(last_message_at=timezone.now())

            # Process mentions
            import re
            mention_pattern = r"@(teacher|parent|student)_(\d+)"
            mentions = re.findall(mention_pattern, content)
            for user_type, user_id in mentions:
                ChatMention.objects.create(
                    message=message,
                    user_type=user_type,
                    user_id=user_id,
                    is_notified=False,
                )

            # Create delivery records for all participants
            self._create_delivery_records(message)

            # Mark this message as read for sender
            MessageReadReceipt.objects.get_or_create(
                message=message,
                user_type="teacher",
                user_id=str(teacher.id),
                defaults={'read_at': timezone.now()}
            )

            serializer = MessageSerializer(
                message,
                context={
                    "request": request,
                    "user_type": "teacher",
                    "user_id": str(teacher.id),
                },
            )

            return Response({
                "success": True, 
                "data": serializer.data,
                "message_id": str(message.id)
            }, status=status.HTTP_201_CREATED)

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherChatMessageListView POST: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

    def _mark_as_delivered_and_read(self, room_id, teacher, messages):
        """Mark messages as delivered and read for teacher"""
        teacher_id_str = str(teacher.id)
        
        for message in messages:
            if message.sender_type != "teacher" or message.sender_id != teacher_id_str:
                # Mark as delivered
                MessageDelivery.objects.update_or_create(
                    message=message,
                    user_type="teacher",
                    user_id=teacher_id_str,
                    defaults={"status": "DELIVERED", "delivered_at": timezone.now()},
                )
                # Mark as read
                MessageReadReceipt.objects.get_or_create(
                    message=message,
                    user_type="teacher",
                    user_id=teacher_id_str,
                    defaults={'read_at': timezone.now()}
                )

    def _mark_all_as_read(self, room_id, teacher):
        """Mark all messages in room as read for teacher"""
        try:
            teacher_id_str = str(teacher.id)
            
            # Get all messages not sent by teacher
            messages = Message.objects.filter(
                room_id=room_id, is_deleted=False
            ).exclude(sender_type="teacher", sender_id=teacher_id_str)

            # Create read receipts for all
            for message in messages:
                MessageReadReceipt.objects.get_or_create(
                    message=message,
                    user_type="teacher",
                    user_id=teacher_id_str,
                    defaults={'read_at': timezone.now()}
                )

            # Update participant's last_read_at
            room = ChatRoom.objects.get(id=room_id)
            participant = room.chatparticipantteacher_set.filter(
                teacher=teacher, is_active=True
            ).first()
            if participant:
                participant.last_read_at = timezone.now()
                participant.save(update_fields=["last_read_at"])

        except Exception as e:
            logger.error(f"Error in _mark_all_as_read: {str(e)}")

    def _create_delivery_records(self, message):
        """Create delivery records for all participants"""
        room = message.room
        teacher_id_str = str(message.sender_id)

        # Parent participants
        parent_participants = room.parents.all()
        for participant in parent_participants:
            MessageDelivery.objects.get_or_create(
                message=message,
                user_type="parent",
                user_id=str(participant.id),
                defaults={"status": "SENT"},
            )

        # Teacher participants (excluding sender)
        teacher_participants = room.teachers.all().exclude(id=message.sender_id)
        for participant in teacher_participants:
            MessageDelivery.objects.get_or_create(
                message=message,
                user_type="teacher",
                user_id=str(participant.id),
                defaults={"status": "SENT"},
            )

        # Student participants
        student_participants = room.students.all()
        for participant in student_participants:
            MessageDelivery.objects.get_or_create(
                message=message,
                user_type="student",
                user_id=str(participant.id),
                defaults={"status": "SENT"},
            )

class TeacherChatMarkAsReadView(APIView):
    """
    POST /teacher/chat/rooms/<room_id>/mark-read/

    Mark all messages in a room as read for teacher
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, room_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Verify teacher has access
            participant = ChatParticipantTeacher.objects.filter(
                room_id=room_id, teacher=teacher, is_active=True
            ).first()

            if not participant:
                return Response(
                    {"success": False, "message": "Not a participant in this room"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            messages = Message.objects.filter(
                room_id=room_id, is_deleted=False
            ).exclude(sender_type="teacher", sender_id=str(teacher.id))

            read_count = 0
            for message in messages:
                receipt, created = MessageReadReceipt.objects.get_or_create(
                    message=message, user_type="teacher", user_id=str(teacher.id)
                )
                if created:
                    read_count += 1

            participant.last_read_at = timezone.now()
            participant.save(update_fields=["last_read_at"])

            return Response(
                {
                    "success": True,
                    "data": {
                        "message": f"Marked {read_count} messages as read",
                        "read_count": read_count,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherChatMarkAsReadView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherChatUnreadCountView(APIView):
    """
    GET /teacher/chat/unread-count/

    Get total unread messages count across all rooms for teacher
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            rooms = ChatRoom.objects.filter(teachers=teacher, is_active=True)

            total_unread = 0

            for room in rooms:
                messages = Message.objects.filter(room=room, is_deleted=False)
                read_messages = MessageReadReceipt.objects.filter(
                    user_type="teacher", user_id=str(teacher.id), message__in=messages
                ).values_list("message_id", flat=True)

                unread = (
                    messages.exclude(id__in=read_messages)
                    .exclude(sender_type="teacher", sender_id=str(teacher.id))
                    .count()
                )

                total_unread += unread

            return Response(
                {
                    "success": True,
                    "data": {
                        "teacher_id": teacher.id,
                        "teacher_name": teacher.full_name,
                        "total_unread": total_unread,
                    },
                }
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherChatUnreadCountView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherChatRoomParticipantsView(APIView):
    """
    GET /chat/rooms/<room_id>/participants/
    """

    permission_classes = [IsAuthenticated]

    def get(self, request, room_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Verify teacher has access to this room
            try:
                room = ChatRoom.objects.get(id=room_id, is_active=True)
            except ChatRoom.DoesNotExist:
                return Response(
                    {"success": False, "message": "Chat room not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Check if teacher is a participant
            is_teacher_participant = ChatParticipantTeacher.objects.filter(
                room=room, teacher=teacher, is_active=True
            ).exists()
            
            if not is_teacher_participant:
                return Response(
                    {"success": False, "message": "You don't have access to this room"},
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Get current teacher's participant record
            current_teacher_participant = ChatParticipantTeacher.objects.filter(
                room=room, teacher=teacher, is_active=True
            ).first()
            is_admin = current_teacher_participant and current_teacher_participant.role == "ADMIN"

            # Get all participants
            participants = {
                "teachers": [],
                "students": [],
                "parents": []
            }

            # Teachers
            teacher_participants = ChatParticipantTeacher.objects.filter(
                room=room, is_active=True
            ).select_related("teacher")

            for tp in teacher_participants:
                participants["teachers"].append({
                    "id": tp.teacher.id,
                    "name": tp.teacher.full_name,
                    "email": tp.teacher.email,
                    "employee_id": tp.teacher.employee_id,
                    "role": tp.role,
                    "is_admin": tp.role == "ADMIN",
                    "is_muted": tp.is_muted,
                    "muted_until": tp.muted_until,
                    "joined_at": tp.joined_at,
                    "last_read_at": tp.last_read_at,
                })

            # Students
            student_participants = ChatParticipantStudent.objects.filter(
                room=room, is_active=True
            ).select_related("student")

            for sp in student_participants:
                participants["students"].append({
                    "id": sp.student.id,
                    "name": sp.student.full_name,
                    "email": sp.student.personal_email,
                    "roll_number": sp.student.roll_number,
                    "student_id": sp.student.student_id,
                    "role": sp.role,
                    "is_admin": sp.role == "ADMIN",
                    "is_muted": sp.is_muted,
                    "muted_until": sp.muted_until,
                    "joined_at": sp.joined_at,
                    "last_read_at": sp.last_read_at,
                })

            # Parents
            parent_participants = ChatParticipantParent.objects.filter(
                room=room, is_active=True
            ).select_related("parent")

            for pp in parent_participants:
                participants["parents"].append({
                    "id": pp.parent.id,
                    "name": pp.parent.full_name,
                    "email": pp.parent.email,
                    "phone": pp.parent.phone,
                    "role": pp.role,
                    "is_admin": pp.role == "ADMIN",
                    "is_muted": pp.is_muted,
                    "muted_until": pp.muted_until,
                    "joined_at": pp.joined_at,
                    "last_read_at": pp.last_read_at,
                })

            total_participants = (
                len(participants["teachers"]) + 
                len(participants["students"]) + 
                len(participants["parents"])
            )

            return Response({
                "success": True,
                "data": {
                    "room_id": str(room.id),
                    "room_name": room.name,
                    "room_type": room.room_type,
                    "current_user": {
                        "type": "teacher",
                        "id": teacher.id,
                        "name": teacher.full_name,
                        "is_admin": is_admin,
                    },
                    "participants": participants,
                    "counts": {
                        "total": total_participants,
                        "teachers": len(participants["teachers"]),
                        "students": len(participants["students"]),
                        "parents": len(participants["parents"]),
                    },
                }
            })

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherChatRoomParticipantsView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

class TeacherMakeRoomAdminView(APIView):
    """
    POST /chat/rooms/<room_id>/make-admin/
    Body: {"user_type": "teacher", "user_id": 123}

    Make a participant an admin in the chat room
    Only existing admins can perform this action
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, room_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get the room
            try:
                room = ChatRoom.objects.get(id=room_id, is_active=True)
            except ChatRoom.DoesNotExist:
                return Response(
                    {"success": False, "message": "Chat room not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Check if current teacher is an admin
            current_participant = ChatParticipantTeacher.objects.filter(
                room=room, teacher=teacher, is_active=True
            ).first()

            if not current_participant or current_participant.role != "ADMIN":
                return Response(
                    {"success": False, "message": "Only admins can make other users admin"},
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Get target user details
            target_user_type = request.data.get("user_type")
            target_user_id = request.data.get("user_id")

            if not target_user_type or not target_user_id:
                return Response(
                    {"success": False, "message": "user_type and user_id are required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Update the participant's role
            updated = False
            if target_user_type == "teacher":
                target_participant = ChatParticipantTeacher.objects.filter(
                    room=room, teacher_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.role = "ADMIN"
                    target_participant.save(update_fields=['role'])
                    updated = True

            elif target_user_type == "student":
                target_participant = ChatParticipantStudent.objects.filter(
                    room=room, student_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.role = "ADMIN"
                    target_participant.save(update_fields=['role'])
                    updated = True

            elif target_user_type == "parent":
                target_participant = ChatParticipantParent.objects.filter(
                    room=room, parent_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.role = "ADMIN"
                    target_participant.save(update_fields=['role'])
                    updated = True

            if not updated:
                return Response(
                    {"success": False, "message": "Participant not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Also update the room's admins JSON field for backward compatibility
            room_admins = room.admins or []
            new_admin = {"type": target_user_type, "id": str(target_user_id)}
            if new_admin not in room_admins:
                room_admins.append(new_admin)
                room.admins = room_admins
                room.save(update_fields=['admins'])

            return Response({
                "success": True,
                "message": f"{target_user_type.capitalize()} is now an admin",
                "data": {
                    "user_type": target_user_type,
                    "user_id": target_user_id,
                    "role": "ADMIN"
                }
            })

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherMakeRoomAdminView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherRemoveRoomAdminView(APIView):
    """
    POST /chat/rooms/<room_id>/remove-admin/
    Body: {"user_type": "teacher", "user_id": 123}

    Remove admin privileges from a participant
    Only existing admins can perform this action
    Cannot remove the last admin
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, room_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get the room
            try:
                room = ChatRoom.objects.get(id=room_id, is_active=True)
            except ChatRoom.DoesNotExist:
                return Response(
                    {"success": False, "message": "Chat room not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Check if current teacher is an admin
            current_participant = ChatParticipantTeacher.objects.filter(
                room=room, teacher=teacher, is_active=True
            ).first()

            if not current_participant or current_participant.role != "ADMIN":
                return Response(
                    {"success": False, "message": "Only admins can remove admin privileges"},
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Get target user details
            target_user_type = request.data.get("user_type")
            target_user_id = request.data.get("user_id")

            if not target_user_type or not target_user_id:
                return Response(
                    {"success": False, "message": "user_type and user_id are required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Cannot remove self as admin
            if target_user_type == "teacher" and str(target_user_id) == str(teacher.id):
                return Response(
                    {"success": False, "message": "You cannot remove your own admin privileges"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Check if this is the last admin
            admin_count = 0
            admin_count += ChatParticipantTeacher.objects.filter(room=room, role="ADMIN", is_active=True).count()
            admin_count += ChatParticipantStudent.objects.filter(room=room, role="ADMIN", is_active=True).count()
            admin_count += ChatParticipantParent.objects.filter(room=room, role="ADMIN", is_active=True).count()

            if admin_count <= 1:
                return Response(
                    {"success": False, "message": "Cannot remove the last admin from the room"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Update the participant's role
            updated = False
            if target_user_type == "teacher":
                target_participant = ChatParticipantTeacher.objects.filter(
                    room=room, teacher_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.role = "MEMBER"
                    target_participant.save(update_fields=['role'])
                    updated = True

            elif target_user_type == "student":
                target_participant = ChatParticipantStudent.objects.filter(
                    room=room, student_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.role = "MEMBER"
                    target_participant.save(update_fields=['role'])
                    updated = True

            elif target_user_type == "parent":
                target_participant = ChatParticipantParent.objects.filter(
                    room=room, parent_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.role = "MEMBER"
                    target_participant.save(update_fields=['role'])
                    updated = True

            if not updated:
                return Response(
                    {"success": False, "message": "Participant not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Also update the room's admins JSON field for backward compatibility
            room_admins = room.admins or []
            admin_to_remove = {"type": target_user_type, "id": str(target_user_id)}
            if admin_to_remove in room_admins:
                room_admins.remove(admin_to_remove)
                room.admins = room_admins
                room.save(update_fields=['admins'])

            return Response({
                "success": True,
                "message": f"Admin privileges removed from {target_user_type}",
                "data": {
                    "user_type": target_user_type,
                    "user_id": target_user_id,
                    "role": "MEMBER"
                }
            })

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherRemoveRoomAdminView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherUpdateParticipantMuteStatusView(APIView):
    """
    POST /chat/rooms/<room_id>/mute-participant/
    Body: {"user_type": "student", "user_id": 123, "muted": true, "muted_until": "2024-12-31T23:59:59Z"}

    Mute or unmute a participant in the chat room
    Only admins and moderators can perform this action
    """

    permission_classes = [IsAuthenticated]

    def post(self, request, room_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            # Get the room
            try:
                room = ChatRoom.objects.get(id=room_id, is_active=True)
            except ChatRoom.DoesNotExist:
                return Response(
                    {"success": False, "message": "Chat room not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Check if current teacher has permission (admin or moderator)
            current_participant = ChatParticipantTeacher.objects.filter(
                room=room, teacher=teacher, is_active=True
            ).first()

            if not current_participant or current_participant.role not in ["ADMIN", "MODERATOR"]:
                return Response(
                    {"success": False, "message": "Only admins and moderators can mute participants"},
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Get target user details
            target_user_type = request.data.get("user_type")
            target_user_id = request.data.get("user_id")
            is_muted = request.data.get("muted", True)
            muted_until = request.data.get("muted_until")

            if not target_user_type or not target_user_id:
                return Response(
                    {"success": False, "message": "user_type and user_id are required"},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Update mute status
            updated = False
            if target_user_type == "teacher":
                target_participant = ChatParticipantTeacher.objects.filter(
                    room=room, teacher_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.is_muted = is_muted
                    if muted_until:
                        target_participant.muted_until = muted_until
                    target_participant.save(update_fields=['is_muted', 'muted_until'])
                    updated = True

            elif target_user_type == "student":
                target_participant = ChatParticipantStudent.objects.filter(
                    room=room, student_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.is_muted = is_muted
                    if muted_until:
                        target_participant.muted_until = muted_until
                    target_participant.save(update_fields=['is_muted', 'muted_until'])
                    updated = True

            elif target_user_type == "parent":
                target_participant = ChatParticipantParent.objects.filter(
                    room=room, parent_id=target_user_id, is_active=True
                ).first()
                if target_participant:
                    target_participant.is_muted = is_muted
                    if muted_until:
                        target_participant.muted_until = muted_until
                    target_participant.save(update_fields=['is_muted', 'muted_until'])
                    updated = True

            if not updated:
                return Response(
                    {"success": False, "message": "Participant not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            return Response({
                "success": True,
                "message": f"{target_user_type.capitalize()} has been {'muted' if is_muted else 'unmuted'}",
                "data": {
                    "user_type": target_user_type,
                    "user_id": target_user_id,
                    "is_muted": is_muted,
                    "muted_until": muted_until
                }
            })

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherUpdateParticipantMuteStatusView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
# =====================================================
# TEACHER LEAVE APPROVAL VIEWS
# =====================================================


class TeacherLeaveTypesView(APIView):
    """
    GET /parent/attendance/leave-types/

    Get list of available leave types with descriptions
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        leave_types = [
            {
                "code": "MEDICAL",
                "name": "Medical Leave",
                "description": "For illness or medical appointments",
            },
            {
                "code": "FAMILY",
                "name": "Family Emergency",
                "description": "For family events or emergencies",
            },
            {
                "code": "EMERGENCY",
                "name": "Emergency",
                "description": "For urgent unforeseen situations",
            },
            {
                "code": "SPORTS",
                "name": "Sports/Event",
                "description": "For sports tournaments or school events",
            },
            {"code": "OTHER", "name": "Other", "description": "Any other valid reason"},
        ]

        return Response({"success": True, "data": leave_types})



class TeacherPendingLeaveRequestsView(APIView):
    """
    GET /api/teacher/leaves/pending/
    
    Get all pending leave requests for classes where teacher is class teacher.
    Returns only PENDING status requests.
    """
    permission_classes = [IsAuthenticated]
    
    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get current academic year
            academic_year = get_request_academic_year(self.request)
            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Get classes where this teacher is class teacher
            teacher_classes = AcademicClass.objects.filter(
                class_teacher=teacher,
                academic_year=academic_year,
                is_active=True
            ).values_list('id', flat=True)
            
            if not teacher_classes:
                return Response(
                    {
                        "success": True,
                        "message": "You are not a class teacher for any active class",
                        "data": [],
                        "statistics": self._get_empty_statistics()
                    },
                    status=status.HTTP_200_OK
                )
            
            # Get pending leave requests for students in these classes
            pending_leaves = AttendanceLeave.objects.filter(
                enrollment__academic_class_id__in=teacher_classes,
                status='PENDING',
                is_active=True
            ).select_related(
                'student', 
                'enrollment',
                'enrollment__academic_class__standard',
                'enrollment__academic_class__section'
            ).order_by('-created_at')
            
            # Apply additional filters from query params
            leave_type = request.query_params.get('leave_type')
            if leave_type:
                pending_leaves = pending_leaves.filter(leave_type=leave_type)
            
            from_date = request.query_params.get('from_date')
            if from_date:
                pending_leaves = pending_leaves.filter(from_date__gte=from_date)
            
            to_date = request.query_params.get('to_date')
            if to_date:
                pending_leaves = pending_leaves.filter(to_date__lte=to_date)
            
            # Pagination
            page = int(request.query_params.get('page', 1))
            page_size = int(request.query_params.get('page_size', 20))
            start = (page - 1) * page_size
            end = start + page_size
            
            total_count = pending_leaves.count()
            paginated_leaves = pending_leaves[start:end]
            
            # Calculate statistics
            statistics = self._get_statistics(pending_leaves)
            
            serializer = LeaveRequestListSerializer(paginated_leaves, many=True)
            
            return Response({
                "success": True,
                "data": {
                    "leaves": serializer.data,
                    "pagination": {
                        "page": page,
                        "page_size": page_size,
                        "total_count": total_count,
                        "total_pages": (total_count + page_size - 1) // page_size
                    },
                    "statistics": statistics
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherPendingLeaveRequestsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _get_statistics(self, queryset):
        """Calculate statistics for pending leaves"""
        return {
            "total_pending": queryset.count(),
            "medical_leaves": queryset.filter(leave_type='MEDICAL').count(),
            "family_leaves": queryset.filter(leave_type='FAMILY').count(),
            "emergency_leaves": queryset.filter(leave_type='EMERGENCY').count(),
            "sports_leaves": queryset.filter(leave_type='SPORTS').count(),
            "other_leaves": queryset.filter(leave_type='OTHER').count()
        }
    
    def _get_empty_statistics(self):
        """Return empty statistics"""
        return {
            "total_pending": 0,
            "medical_leaves": 0,
            "family_leaves": 0,
            "emergency_leaves": 0,
            "sports_leaves": 0,
            "other_leaves": 0
        }


class TeacherAllLeaveRequestsView(APIView):
    """
    GET /api/teacher/leaves/
    
    Get all leave requests (all statuses) for classes where teacher is class teacher.
    Supports filtering by status, leave_type, date range.
    """
    permission_classes = [IsAuthenticated]
    
    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get current academic year
            academic_year = get_request_academic_year(self.request)
            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Get classes where this teacher is class teacher
            teacher_classes = AcademicClass.objects.filter(
                class_teacher=teacher,
                academic_year=academic_year,
                is_active=True
            ).values_list('id', flat=True)
            
            if not teacher_classes:
                return Response(
                    {
                        "success": True,
                        "message": "You are not a class teacher for any active class",
                        "data": [],
                        "statistics": self._get_empty_statistics()
                    },
                    status=status.HTTP_200_OK
                )
            
            # Base queryset
            leaves = AttendanceLeave.objects.filter(
                enrollment__academic_class_id__in=teacher_classes,
                is_active=True
            ).select_related(
                'student', 
                'enrollment',
                'enrollment__academic_class__standard',
                'enrollment__academic_class__section'
            ).order_by('-created_at')
            
            # Apply filters
            status_filter = request.query_params.get('status')
            if status_filter:
                leaves = leaves.filter(status=status_filter)
            
            leave_type = request.query_params.get('leave_type')
            if leave_type:
                leaves = leaves.filter(leave_type=leave_type)
            
            from_date = request.query_params.get('from_date')
            if from_date:
                leaves = leaves.filter(from_date__gte=from_date)
            
            to_date = request.query_params.get('to_date')
            if to_date:
                leaves = leaves.filter(to_date__lte=to_date)
            
            student_id = request.query_params.get('student_id')
            if student_id:
                leaves = leaves.filter(student_id=student_id)
            
            # Pagination
            page = int(request.query_params.get('page', 1))
            page_size = int(request.query_params.get('page_size', 20))
            start = (page - 1) * page_size
            end = start + page_size
            
            total_count = leaves.count()
            paginated_leaves = leaves[start:end]
            
            # Calculate statistics
            statistics = self._get_statistics(leaves)
            
            serializer = LeaveRequestListSerializer(paginated_leaves, many=True)
            
            return Response({
                "success": True,
                "data": {
                    "leaves": serializer.data,
                    "pagination": {
                        "page": page,
                        "page_size": page_size,
                        "total_count": total_count,
                        "total_pages": (total_count + page_size - 1) // page_size
                    },
                    "statistics": statistics,
                    "filters_applied": {
                        "status": status_filter,
                        "leave_type": leave_type,
                        "from_date": from_date,
                        "to_date": to_date,
                        "student_id": student_id
                    }
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherAllLeaveRequestsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _get_statistics(self, queryset):
        """Calculate comprehensive statistics"""
        return {
            "total": queryset.count(),
            "pending": queryset.filter(status='PENDING').count(),
            "approved": queryset.filter(status='APPROVED').count(),
            "rejected": queryset.filter(status='REJECTED').count(),
            "medical_leaves": queryset.filter(leave_type='MEDICAL').count(),
            "family_leaves": queryset.filter(leave_type='FAMILY').count(),
            "emergency_leaves": queryset.filter(leave_type='EMERGENCY').count(),
            "sports_leaves": queryset.filter(leave_type='SPORTS').count(),
            "other_leaves": queryset.filter(leave_type='OTHER').count()
        }
    
    def _get_empty_statistics(self):
        """Return empty statistics"""
        return {
            "total": 0,
            "pending": 0,
            "approved": 0,
            "rejected": 0,
            "medical_leaves": 0,
            "family_leaves": 0,
            "emergency_leaves": 0,
            "sports_leaves": 0,
            "other_leaves": 0
        }


class TeacherLeaveRequestDetailView(APIView):
    """
    GET /api/teacher/leaves/{id}/
    
    Get detailed information about a specific leave request.
    Verifies teacher is class teacher before returning data.
    """
    permission_classes = [IsAuthenticated]
    
    def get(self, request, leave_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get the leave request with related data
            leave = AttendanceLeave.objects.filter(
                id=leave_id,
                is_active=True
            ).select_related(
                'student',
                'enrollment',
                'enrollment__academic_class__standard',
                'enrollment__academic_class__section',
                'approved_by'
            ).first()
            
            if not leave:
                return Response(
                    {"success": False, "message": "Leave request not found"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Verify teacher has permission (is class teacher of this student's class)
            if not self._has_permission(teacher, leave):
                return Response(
                    {"success": False, "message": "You don't have permission to view this leave request"},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            serializer = LeaveRequestDetailSerializer(leave)
            
            return Response({
                "success": True,
                "data": serializer.data
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherLeaveRequestDetailView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _has_permission(self, teacher, leave):
        """Check if teacher is class teacher of the student's class"""
        if not leave.enrollment or not leave.enrollment.academic_class:
            return False
        
        academic_year = get_request_academic_year(self.request)
        
        return AcademicClass.objects.filter(
            id=leave.enrollment.academic_class.id,
            class_teacher=teacher,
            academic_year=academic_year,
            is_active=True
        ).exists()


class TeacherApproveLeaveView(APIView):
    """
    POST /api/teacher/leaves/{id}/approve/
    
    Approve a leave request.
    Creates attendance records for the leave period with status='LEAVE'.
    """
    permission_classes = [IsAuthenticated]
    
    def post(self, request, leave_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get the leave request
            leave = AttendanceLeave.objects.filter(
                id=leave_id,
                is_active=True
            ).select_related(
                'student',
                'enrollment',
                'enrollment__academic_class'
            ).first()
            
            if not leave:
                return Response(
                    {"success": False, "message": "Leave request not found"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Verify teacher has permission
            if not self._has_permission(teacher, leave):
                return Response(
                    {"success": False, "message": "You don't have permission to approve this leave request"},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            # Check if already processed
            if leave.status != 'PENDING':
                return Response(
                    {"success": False, "message": f"Leave request is already {leave.status.lower()}"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            # Validate serializer
            serializer = LeaveApproveSerializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"success": False, "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            remarks = serializer.validated_data.get('remarks', '')
            
            # Process approval with transaction
            with transaction.atomic():
                # Update leave status
                leave.status = 'APPROVED'
                leave.approved_by = teacher
                leave.approved_at = timezone.now()
                leave.rejection_reason = ''
                leave.save()
                
                # Create attendance records for the leave period
                attendance_created = self._create_leave_attendance_records(leave, teacher, remarks)
                
                logger.info(
                    f"Leave approved: {leave.id} for student {leave.student.id} "
                    f"by teacher {teacher.id}. Created {attendance_created} attendance records."
                )
            
            return Response({
                "success": True,
                "message": f"Leave request approved successfully. {attendance_created} attendance records created.",
                "data": {
                    "leave_id": leave.id,
                    "status": leave.status,
                    "approved_at": leave.approved_at,
                    "attendance_records_created": attendance_created
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherApproveLeaveView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _has_permission(self, teacher, leave):
        """Check if teacher is class teacher"""
        if not leave.enrollment or not leave.enrollment.academic_class:
            return False
        
        academic_year = get_request_academic_year(self.request)
        
        return AcademicClass.objects.filter(
            id=leave.enrollment.academic_class.id,
            class_teacher=teacher,
            academic_year=academic_year,
            is_active=True
        ).exists()
    def _create_leave_attendance_records(self, leave, teacher, remarks):
        """Create attendance records for each day in the leave period."""
        from datetime import timedelta
        
        academic_class = leave.enrollment.academic_class
        current_date = leave.from_date
        created_count = 0
        
        while current_date <= leave.to_date:
            # ✅ CORRECT - Properly unpack the tuple
            session, created = AttendanceSession.objects.get_or_create(
                academic_class=academic_class,
                date=current_date,
                session_type='FULL_DAY',
                defaults={
                    'taken_by': teacher,
                    'status': 'SUBMITTED',
                    'total_students': StudentEnrollment.objects.filter(
                        academic_class=academic_class, is_active=True
                    ).count(),
                    'remarks': f"Auto-created for leave approval: {remarks[:200]}" if remarks else "Auto-created for leave approval"
                }
            )
            
            # Now 'created' tells you if a new session was created
            # You don't need to use it if you don't want to
            
            # Create or update attendance record
            attendance, attendance_created = StudentAttendance.objects.update_or_create(
                session=session,
                enrollment=leave.enrollment,
                defaults={
                    'student': leave.student,
                    'status': 'LEAVE',
                    'remarks': f"Approved leave: {leave.get_leave_type_display()} - {leave.reason[:100]}",
                    'marked_by': teacher,
                    'leave': leave
                }
            )
            
            if attendance_created:
                created_count += 1
                # Update session counts
                session.update_counts()
            
            current_date += timedelta(days=1)
        
        return created_count

class TeacherRejectLeaveView(APIView):
    """
    POST /api/teacher/leaves/{id}/reject/
    
    Reject a leave request with a reason.
    """
    permission_classes = [IsAuthenticated]
    
    def post(self, request, leave_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get the leave request
            leave = AttendanceLeave.objects.filter(
                id=leave_id,
                is_active=True
            ).select_related(
                'student',
                'enrollment'
            ).first()
            
            if not leave:
                return Response(
                    {"success": False, "message": "Leave request not found"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Verify teacher has permission
            if not self._has_permission(teacher, leave):
                return Response(
                    {"success": False, "message": "You don't have permission to reject this leave request"},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            # Check if already processed
            if leave.status != 'PENDING':
                return Response(
                    {"success": False, "message": f"Leave request is already {leave.status.lower()}"},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            # Validate serializer
            serializer = LeaveRejectSerializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"success": False, "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            rejection_reason = serializer.validated_data['rejection_reason']
            
            # Update leave status
            leave.status = 'REJECTED'
            leave.approved_by = teacher
            leave.approved_at = timezone.now()
            leave.rejection_reason = rejection_reason
            leave.save()
            
            logger.info(
                f"Leave rejected: {leave.id} for student {leave.student.id} "
                f"by teacher {teacher.id}. Reason: {rejection_reason[:100]}"
            )
            
            return Response({
                "success": True,
                "message": "Leave request rejected successfully",
                "data": {
                    "leave_id": leave.id,
                    "status": leave.status,
                    "rejected_at": leave.approved_at,
                    "rejection_reason": leave.rejection_reason
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherRejectLeaveView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _has_permission(self, teacher, leave):
        """Check if teacher is class teacher"""
        if not leave.enrollment or not leave.enrollment.academic_class:
            return False
        
        academic_year = get_request_academic_year(self.request)
        
        return AcademicClass.objects.filter(
            id=leave.enrollment.academic_class.id,
            class_teacher=teacher,
            academic_year=academic_year,
            is_active=True
        ).exists()


class TeacherBulkLeaveActionView(APIView):
    """
    POST /api/teacher/leaves/bulk-action/
    
    Bulk approve or reject multiple leave requests at once.
    """
    permission_classes = [IsAuthenticated]
    
    def post(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Validate serializer
            serializer = BulkLeaveActionSerializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"success": False, "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            leave_ids = serializer.validated_data['leave_ids']
            action = serializer.validated_data['action']
            rejection_reason = serializer.validated_data.get('rejection_reason', '')
            remarks = serializer.validated_data.get('remarks', '')
            
            # Get leave requests
            leaves = AttendanceLeave.objects.filter(
                id__in=leave_ids,
                status='PENDING',
                is_active=True
            ).select_related(
                'student',
                'enrollment',
                'enrollment__academic_class'
            )
            
            if not leaves.exists():
                return Response(
                    {"success": False, "message": "No pending leave requests found with the provided IDs"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Filter leaves where teacher has permission
            valid_leaves = []
            invalid_ids = []
            
            for leave in leaves:
                if self._has_permission(teacher, leave):
                    valid_leaves.append(leave)
                else:
                    invalid_ids.append(leave.id)
            
            if not valid_leaves:
                return Response(
                    {"success": False, "message": "You don't have permission to process any of the selected leave requests"},
                    status=status.HTTP_403_FORBIDDEN
                )
            
            # Process bulk action
            processed_count = 0
            attendance_records_created = 0
            
            with transaction.atomic():
                for leave in valid_leaves:
                    if action == 'approve':
                        leave.status = 'APPROVED'
                        leave.approved_by = teacher
                        leave.approved_at = timezone.now()
                        leave.rejection_reason = ''
                        leave.save()
                        
                        # Create attendance records
                        attendance_records_created += self._create_leave_attendance_records(
                            leave, teacher, remarks
                        )
                        processed_count += 1
                        
                    elif action == 'reject':
                        if not rejection_reason:
                            rejection_reason = "Bulk rejection - no specific reason provided"
                        
                        leave.status = 'REJECTED'
                        leave.approved_by = teacher
                        leave.approved_at = timezone.now()
                        leave.rejection_reason = rejection_reason
                        leave.save()
                        processed_count += 1
            
            logger.info(
                f"Bulk {action} action completed by teacher {teacher.id}. "
                f"Processed: {processed_count} leaves. Invalid: {len(invalid_ids)}"
            )
            
            return Response({
                "success": True,
                "message": f"Successfully {action}d {processed_count} leave requests",
                "data": {
                    "action": action,
                    "processed_count": processed_count,
                    "invalid_ids": invalid_ids if invalid_ids else None,
                    "attendance_records_created": attendance_records_created if action == 'approve' else None
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherBulkLeaveActionView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _has_permission(self, teacher, leave):
        """Check if teacher is class teacher"""
        if not leave.enrollment or not leave.enrollment.academic_class:
            return False
        
        academic_year = get_request_academic_year(self.request)
        
        return AcademicClass.objects.filter(
            id=leave.enrollment.academic_class.id,
            class_teacher=teacher,
            academic_year=academic_year,
            is_active=True
        ).exists()
    
    def _create_leave_attendance_records(self, leave, teacher, remarks):
        """Create attendance records for leave period"""
        from datetime import timedelta
        
        academic_class = leave.enrollment.academic_class
        current_date = leave.from_date
        created_count = 0
        
        while current_date <= leave.to_date:
            session, _ = AttendanceSession.objects.get_or_create(
                academic_class=academic_class,
                date=current_date,
                session_type='FULL_DAY',
                defaults={
                    'taken_by': teacher,
                    'status': 'SUBMITTED',
                    'total_students': StudentEnrollment.objects.filter(
                        academic_class=academic_class, is_active=True
                    ).count(),
                    'remarks': f"Auto-created for leave approval"
                }
            )
            
            attendance, created = StudentAttendance.objects.update_or_create(
                session=session,
                enrollment=leave.enrollment,
                defaults={
                    'student': leave.student,
                    'status': 'LEAVE',
                    'remarks': f"Approved leave: {leave.leave_type}",
                    'marked_by': teacher,
                    'leave': leave
                }
            )
            
            if created:
                created_count += 1
                session.update_counts()
            
            current_date += timedelta(days=1)
        
        return created_count


class TeacherLeaveStatisticsView(APIView):
    """
    GET /api/teacher/leaves/statistics/
    
    Get comprehensive leave statistics for class teacher's classes.
    """
    permission_classes = [IsAuthenticated]
    
    def get(self, request):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)
            
            # Get current academic year
            academic_year = get_request_academic_year(self.request)
            if not academic_year:
                return Response(
                    {"success": False, "message": "No active academic year found"},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Get classes where this teacher is class teacher
            teacher_classes = AcademicClass.objects.filter(
                class_teacher=teacher,
                academic_year=academic_year,
                is_active=True
            ).values_list('id', flat=True)
            
            if not teacher_classes:
                return Response({
                    "success": True,
                    "data": {
                        "overall": self._get_empty_overall_stats(),
                        "by_class": [],
                        "by_leave_type": self._get_empty_leave_type_stats()
                    }
                })
            
            # Base queryset
            leaves = AttendanceLeave.objects.filter(
                enrollment__academic_class_id__in=teacher_classes,
                is_active=True
            )
            
            # Overall statistics
            leave_count = leaves.count()
            # Compute average leave duration in Python to avoid timedelta/float cast error
            if leave_count > 0:
                date_pairs = leaves.values_list('from_date', 'to_date')
                total_days = sum((to_d - from_d).days + 1 for from_d, to_d in date_pairs if to_d and from_d)
                avg_days = round(total_days / leave_count, 1)
            else:
                avg_days = 0

            overall = {
                "total_leaves": leave_count,
                "pending": leaves.filter(status='PENDING').count(),
                "approved": leaves.filter(status='APPROVED').count(),
                "rejected": leaves.filter(status='REJECTED').count(),
                "total_students_affected": leaves.values('student_id').distinct().count(),
                "average_days_per_leave": avg_days
            }
            
            # Statistics by class
            by_class = []
            for class_id in teacher_classes:
                academic_class = AcademicClass.objects.filter(id=class_id).first()
                class_leaves = leaves.filter(enrollment__academic_class_id=class_id)
                
                by_class.append({
                    "class_id": class_id,
                    "class_name": str(academic_class) if academic_class else "Unknown",
                    "total_leaves": class_leaves.count(),
                    "pending": class_leaves.filter(status='PENDING').count(),
                    "approved": class_leaves.filter(status='APPROVED').count(),
                    "rejected": class_leaves.filter(status='REJECTED').count(),
                    "students_count": class_leaves.values('student_id').distinct().count()
                })
            
            # Statistics by leave type
            by_leave_type = {
                "MEDICAL": leaves.filter(leave_type='MEDICAL').count(),
                "FAMILY": leaves.filter(leave_type='FAMILY').count(),
                "EMERGENCY": leaves.filter(leave_type='EMERGENCY').count(),
                "SPORTS": leaves.filter(leave_type='SPORTS').count(),
                "OTHER": leaves.filter(leave_type='OTHER').count()
            }
            
            # Monthly trend (last 6 months)
            from datetime import timedelta
            six_months_ago = timezone.now().date() - timedelta(days=180)

            monthly_trend = list(
                leaves.filter(
                    created_at__date__gte=six_months_ago
                ).annotate(
                    year=ExtractYear('created_at'),
                    month=ExtractMonth('created_at'),
                ).values('year', 'month').annotate(
                    count=Count('id'),
                    approved=Count('id', filter=Q(status='APPROVED')),
                    rejected=Count('id', filter=Q(status='REJECTED'))
                ).order_by('-year', '-month')
            )
            
            return Response({
                "success": True,
                "data": {
                    "overall": overall,
                    "by_class": by_class,
                    "by_leave_type": by_leave_type,
                    "monthly_trend": monthly_trend
                }
            })
            
        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error in TeacherLeaveStatisticsView: {str(e)}")
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _get_empty_overall_stats(self):
        return {
            "total_leaves": 0,
            "pending": 0,
            "approved": 0,
            "rejected": 0,
            "total_students_affected": 0,
            "average_days_per_leave": 0
        }
    
    def _get_empty_leave_type_stats(self):
        return {
            "MEDICAL": 0,
            "FAMILY": 0,
            "EMERGENCY": 0,
            "SPORTS": 0,
            "OTHER": 0
        }

class TeacherDeleteGroupView(APIView):
    """
    DELETE /teacher/chat/rooms/<room_id>/

    Permanently delete a CLASS or SUBJECT group chat created by this teacher.
    Only the teacher who holds ADMIN role in the room can delete it.
    All messages are removed via CASCADE.
    """

    permission_classes = [IsAuthenticated]

    def delete(self, request, room_id):
        try:
            teacher = Teacher.objects.get(external_user_id=request.user.id)

            try:
                room = ChatRoom.objects.get(id=room_id, is_active=True)
            except ChatRoom.DoesNotExist:
                return Response(
                    {"success": False, "message": "Chat room not found"},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Only CLASS and SUBJECT groups can be deleted this way
            if room.room_type not in ("CLASS", "SUBJECT"):
                return Response(
                    {"success": False, "message": "Only class or subject groups can be deleted."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Teacher must be an ADMIN participant
            participant = ChatParticipantTeacher.objects.filter(
                room=room, teacher=teacher, is_active=True, role="ADMIN"
            ).first()

            if not participant:
                return Response(
                    {"success": False, "message": "You do not have permission to delete this group."},
                    status=status.HTTP_403_FORBIDDEN,
                )

            room_name = room.name
            room_type = room.room_type

            # Hard delete — messages cascade from ChatRoom FK
            room.delete()

            log_teacher_activity(
                teacher=teacher,
                action='DELETE_GROUP',
                description=f'Deleted {room_type.lower()} group "{room_name}"',
                metadata={'room_id': str(room_id), 'room_type': room_type, 'room_name': room_name},
            )
            logger.info(
                f"Teacher {teacher.full_name} ({teacher.id}) deleted {room_type} group '{room_name}' (room_id={room_id})"
            )

            return Response(
                {"success": True, "message": f"Group '{room_name}' deleted successfully."},
                status=status.HTTP_200_OK,
            )

        except Teacher.DoesNotExist:
            return Response(
                {"success": False, "message": "Teacher not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            logger.error(f"Error in TeacherDeleteGroupView: {str(e)}", exc_info=True)
            return Response(
                {"success": False, "message": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class TeacherAcademicYearsView(APIView):
    """
    List academic years, newest first. Powers the academic-year switcher
    in the teacher app's Settings screen.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            years = AcademicYear.objects.all().order_by("-start_date")
            active = AcademicYear.objects.filter(is_active=True).order_by(
                "-start_date"
            ).first()
            data = AcademicYearSerializer(years, many=True).data
            return Response(
                {
                    "success": True,
                    "count": len(data),
                    "active_year_id": active.id if active else None,
                    "years": data,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            logger.error(f"Error in TeacherAcademicYearsView: {str(e)}")
            return Response(
                {"success": False, "message": "Failed to load academic years"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


