from rest_framework import serializers
from people.models import Parent, Student
from django.db import models
from django.utils import timezone
from exam.models import (
    Exam, ExamType, ExamSubject, StudentMarks, 
    StudentExamRegistration, ExamResult
)
from academics.models import AcademicYear, StudentEnrollment, AcademicClass, Section
from academics.serializers import (
    AcademicYearSerializer,
    StudentEnrollmentSerializer,
    AcademicClassSerializer,
)

from transport.models import (
    TransportType,
    TransportVehicle,
    Route,
    Stop,
    StudentTransport,
    TeacherTransport,
)

from attendance.models import (
    AttendanceSession,
    StudentAttendance,
    AttendanceSummary,
    AttendanceLeave,
)
from announcements.models import (
    CommonAnnouncement,
    StudentAnnouncement,
    AnnouncementType,
)
from fee.serializers import StudentFeeAssignmentSerializer, ClassFeeStructureSerializer

from fee.models import FeePayment

# Import timetable models
from schedules.models import TimeTable, WeekDay
from academics.models import Subject, SubjectTeacher
from people.models import Teacher


# =====================================================
# AUTHENTICATION SERIALIZERS
# =====================================================


class ParentLoginSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)


class VerifyOTPSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)
    otp = serializers.CharField(required=True, max_length=6)


# =====================================================
# ACADEMICS SERIALIZERS (for nested usage)
# =====================================================


class SectionSerializer(serializers.ModelSerializer):
    """Serializer for Section model"""

    class Meta:
        model = Section
        fields = ["id", "name", "code"]


# =====================================================
# STUDENT SERIALIZERS
# =====================================================


class StudentSerializer(serializers.ModelSerializer):
    """Serializer for Student model with all relevant fields"""

    full_name = serializers.SerializerMethodField()
    age = serializers.SerializerMethodField()
    permanent_address = serializers.SerializerMethodField()
    correspondence_address = serializers.SerializerMethodField()

    class Meta:
        model = Student
        fields = [
            # Basic Info
            "id",
            "external_user_id",
            "student_id",
            "roll_number",
            "admission_number",
            # Name Fields
            "first_name",
            "middle_name",
            "last_name",
            "full_name",
            # Personal Details
            "date_of_birth",
            "age",
            "gender",
            # Contact Info
            "personal_email",
            "personal_phone",
            # Addresses
            "permanent_address",
            "correspondence_address",
            # Academic
            "admission_date",
            # Identification
            "identification_type",
            "identification_number",
            # Health
            "blood_group",
            "known_allergies",
            "medical_conditions",
            # Emergency Contact
            "emergency_contact_name",
            "emergency_contact_phone",
            "emergency_contact_relation",
            # Status & Media
            "profile_image",
            "is_active",
            # Timestamps
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at", "external_user_id"]

    def get_full_name(self, obj):
        """Return full name combining first, middle, and last name"""
        parts = [obj.first_name, obj.middle_name, obj.last_name]
        return " ".join(filter(None, parts))

    def get_age(self, obj):
        """Calculate age from date of birth"""
        return obj.age

    def get_permanent_address(self, obj):
        """Format permanent address as a single string"""
        if not any(
            [
                obj.permanent_address_line_1,
                obj.permanent_address_line_2,
                obj.permanent_city,
                obj.permanent_state,
                obj.permanent_country,
                obj.permanent_pincode,
            ]
        ):
            return None

        address_parts = []
        if obj.permanent_address_line_1:
            address_parts.append(obj.permanent_address_line_1)
        if obj.permanent_address_line_2:
            address_parts.append(obj.permanent_address_line_2)

        city_state = []
        if obj.permanent_city:
            city_state.append(obj.permanent_city)
        if obj.permanent_state:
            city_state.append(obj.permanent_state)
        if city_state:
            address_parts.append(", ".join(city_state))

        if obj.permanent_country:
            address_parts.append(obj.permanent_country)
        if obj.permanent_pincode:
            address_parts.append(obj.permanent_pincode)

        return ", ".join(address_parts)

    def get_correspondence_address(self, obj):
        """Format correspondence address as a single string"""
        if not any(
            [
                obj.correspondence_address_line_1,
                obj.correspondence_address_line_2,
                obj.correspondence_city,
                obj.correspondence_state,
                obj.correspondence_country,
                obj.correspondence_pincode,
            ]
        ):
            return None

        address_parts = []
        if obj.correspondence_address_line_1:
            address_parts.append(obj.correspondence_address_line_1)
        if obj.correspondence_address_line_2:
            address_parts.append(obj.correspondence_address_line_2)

        city_state = []
        if obj.correspondence_city:
            city_state.append(obj.correspondence_city)
        if obj.correspondence_state:
            city_state.append(obj.correspondence_state)
        if city_state:
            address_parts.append(", ".join(city_state))

        if obj.correspondence_country:
            address_parts.append(obj.correspondence_country)
        if obj.correspondence_pincode:
            address_parts.append(obj.correspondence_pincode)

        return ", ".join(address_parts)


class StudentDetailSerializer(serializers.Serializer):
    """
    Comprehensive serializer for student detail view
    Combines student data with relationship and enrollment information
    """

    student = StudentSerializer()
    relationship_info = serializers.SerializerMethodField()
    current_academic_year = AcademicYearSerializer()
    current_enrollment = StudentEnrollmentSerializer(allow_null=True)
    enrollment_history = StudentEnrollmentSerializer(many=True)

    def get_relationship_info(self, obj):
        """Extract relationship info from student_parent"""
        student_parent = obj.get("student_parent")
        if student_parent:
            return {
                "relationship": student_parent.relationship,
                "is_primary_contact": student_parent.is_primary_contact,
                "can_pickup": student_parent.can_pickup,
            }
        return None

    def to_representation(self, instance):
        """Override to structure the response"""
        data = super().to_representation(instance)

        # Flatten the structure - move student fields to top level
        student_data = data.pop("student", {})
        result = {**student_data, **data}

        return result


class ParentStudentListSerializer(serializers.Serializer):
    """
    Minimal serializer for parent's students list
    Returns only essential fields with enrollment info
    """

    id = serializers.IntegerField(read_only=True)
    external_user_id = serializers.CharField(read_only=True)
    full_name = serializers.SerializerMethodField()
    relationship = serializers.CharField(read_only=True)
    is_primary_contact = serializers.BooleanField(read_only=True)
    can_pickup = serializers.BooleanField(read_only=True)
    current_academic_year = serializers.SerializerMethodField()

    def get_full_name(self, obj):
        """Get full name from student object"""
        if hasattr(obj, "full_name") and obj.full_name:
            return obj.full_name
        parts = []
        if hasattr(obj, "first_name") and obj.first_name:
            parts.append(obj.first_name)
        if hasattr(obj, "middle_name") and obj.middle_name:
            parts.append(obj.middle_name)
        if hasattr(obj, "last_name") and obj.last_name:
            parts.append(obj.last_name)
        return " ".join(filter(None, parts)) if parts else None

    def get_current_academic_year(self, obj):
        """Get current academic year info (populated in view)"""
        return getattr(obj, "_current_academic_year", None)


# =====================================================
# PARENT SERIALIZERS
# =====================================================


class ParentSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(source="user.email", read_only=True)
    full_name = serializers.SerializerMethodField()

    class Meta:
        model = Parent
        fields = [
            "id",
            "external_user_id",
            "email",
            "first_name",
            "last_name",
            "full_name",
            "phone",
            "alternate_phone",
            "profile_image",
            "occupation",
            "address_line_1",
            "city",
            "state",
            "country",
            "pincode",
            "is_primary",
        ]
        read_only_fields = ["id", "external_user_id", "user_id"]

    def get_full_name(self, obj):
        """Return full name of parent"""
        parts = [obj.first_name, obj.last_name]
        return " ".join(filter(None, parts))


# =====================================================
# TIMETABLE SERIALIZERS FOR PARENT APP
# =====================================================


# Add this to your serializers.py file
class WeekDaySerializer(serializers.ModelSerializer):
    """
    Serializer for WeekDay model
    """

    class Meta:
        model = WeekDay
        fields = ["id", "day_name", "day_code", "is_open", "start_time", "end_time"]


class ParentWeekDaySerializer(serializers.ModelSerializer):
    """Simple WeekDay serializer for parent app"""

    class Meta:
        model = WeekDay
        fields = ["id", "day_code", "day_name", "is_open", "start_time", "end_time"]


class ParentSubjectSerializer(serializers.ModelSerializer):
    """Simple Subject serializer for parent app"""

    class Meta:
        model = Subject
        fields = ["id", "name", "code"]


class ParentTeacherSerializer(serializers.ModelSerializer):
    """Simple Teacher serializer for parent app"""

    full_name = serializers.SerializerMethodField()

    class Meta:
        model = Teacher
        fields = ["id", "full_name", "employee_id"]

    def get_full_name(self, obj):
        return obj.full_name


class ParentTimeTableSerializer(serializers.ModelSerializer):
    """Serializer for parent timetable view - minimal and efficient"""

    subject_name = serializers.CharField(source="subject.name", read_only=True)
    subject_code = serializers.CharField(source="subject.code", read_only=True)
    teacher_name = serializers.SerializerMethodField()
    weekday_name = serializers.CharField(source="weekday.day_name", read_only=True)
    weekday_code = serializers.CharField(source="weekday.day_code", read_only=True)

    class Meta:
        model = TimeTable
        fields = [
            "id",
            "period_number",
            "start_time",
            "end_time",
            "subject_name",
            "subject_code",
            "teacher_name",
            "weekday_name",
            "weekday_code",
            "room_number",
            "is_break",
            "is_substitution",
            "notes",
        ]

    def get_teacher_name(self, obj):
        """Get teacher name considering substitution"""
        if obj.is_substitution and obj.substitute_teacher:
            return obj.substitute_teacher.full_name
        if obj.subject_teacher and obj.subject_teacher.teacher:
            return obj.subject_teacher.teacher.full_name
        return None


class ParentClassTimetableSerializer(serializers.Serializer):
    """Serializer for class timetable grouped by weekday"""

    weekday_id = serializers.IntegerField()
    weekday_name = serializers.CharField()
    weekday_code = serializers.CharField()
    periods = ParentTimeTableSerializer(many=True)


class ParentAcademicClassForTimetableSerializer(serializers.ModelSerializer):
    """Academic Class serializer for timetable views"""

    class_name = serializers.SerializerMethodField()
    standard_name = serializers.CharField(source="standard.name", read_only=True)
    section_name = serializers.CharField(source="section.name", read_only=True)
    academic_year_name = serializers.CharField(
        source="academic_year.name", read_only=True
    )

    class Meta:
        model = AcademicClass
        fields = [
            "id",
            "class_name",
            "standard_name",
            "section_name",
            "academic_year_name",
        ]

    def get_class_name(self, obj):
        return str(obj)


class ParentStudentTimetableResponseSerializer(serializers.Serializer):
    """Serializer for student timetable response"""

    success = serializers.BooleanField(default=True)
    class_info = ParentAcademicClassForTimetableSerializer()
    timetable = ParentClassTimetableSerializer(many=True)


class ParentStudentAllTimetablesResponseSerializer(serializers.Serializer):
    """Serializer for all timetables response"""

    success = serializers.BooleanField(default=True)
    count = serializers.IntegerField()
    data = serializers.ListField(child=ParentStudentTimetableResponseSerializer())


class ParentWeekdayTimetableResponseSerializer(serializers.Serializer):
    """Serializer for weekday-specific timetable response"""

    success = serializers.BooleanField(default=True)
    weekday_info = ParentWeekDaySerializer()
    periods = ParentTimeTableSerializer(many=True)


class StudentFeeDetailSerializer(serializers.Serializer):
    """Main serializer for student fee details"""

    # Fix 1: Use source="class_fee_structure" to map to the actual field name
    fee_structure = ClassFeeStructureSerializer(
        source="class_fee_structure", read_only=True
    )

    # Fix 2: Remove the source="*" as it might cause issues
    student_assignment = serializers.SerializerMethodField()

    effective_due_date = serializers.SerializerMethodField()
    payment_status = serializers.SerializerMethodField()
    amount_paid = serializers.SerializerMethodField()
    balance_due = serializers.SerializerMethodField()

    def get_student_assignment(self, obj):
        """Return student assignment details"""
        return {
            "id": obj.id,
            "discount_type": obj.discount_type,
            "discount_value": obj.discount_value,
            "due_date_override": obj.due_date_override,
            "is_active": obj.is_active,
            "reason": obj.reason,
        }

    def get_effective_due_date(self, obj):
        """Get the effective due date (override if exists)"""
        return obj.due_date_override or obj.class_fee_structure.due_date

    def get_payment_status(self, obj):
        """Determine payment status for this fee assignment"""
        # Get all payments for this assignment
        payments = obj.payments.filter(status="completed")
        total_paid = payments.aggregate(total=models.Sum("amount_paid"))["total"] or 0

        final_amount = obj.calculate_final_amount()

        if total_paid >= final_amount:
            return "paid"
        elif total_paid > 0:
            return "partial"
        else:
            # Check if due date has passed
            effective_due_date = self.get_effective_due_date(obj)
            if effective_due_date and effective_due_date < timezone.now().date():
                return "overdue"
            return "pending"

    def get_amount_paid(self, obj):
        """Get total amount paid for this fee assignment"""
        payments = obj.payments.filter(status="completed")
        total_paid = payments.aggregate(total=models.Sum("amount_paid"))["total"] or 0
        return total_paid

    def get_balance_due(self, obj):
        """Get remaining balance for this fee assignment"""
        final_amount = obj.calculate_final_amount()
        total_paid = self.get_amount_paid(obj)
        return max(0, final_amount - total_paid)


class FeePaymentHistorySerializer(serializers.ModelSerializer):
    """Serializer for payment history"""

    payment_method_display = serializers.CharField(source="get_payment_method_display")
    status_display = serializers.CharField(source="get_status_display")

    class Meta:
        model = FeePayment
        fields = [
            "id",
            "receipt_number",
            "amount_paid",
            "payment_date",
            "payment_method",
            "payment_method_display",
            "status",
            "status_display",
            "transaction_reference",
            "cheque_number",
            "bank_name",
            "principal_amount",
            "late_fee_amount",
            "is_bounced",
            "notes",
            "created_at",
        ]


class FeePaymentHistorySerializer(serializers.ModelSerializer):
    """Serializer for payment history"""

    payment_method_display = serializers.CharField(source="get_payment_method_display")
    status_display = serializers.CharField(source="get_status_display")

    class Meta:
        model = FeePayment
        fields = [
            "id",
            "receipt_number",
            "amount_paid",
            "payment_date",
            "payment_method",
            "payment_method_display",
            "status",
            "status_display",
            "transaction_reference",
            "cheque_number",
            "bank_name",
            "principal_amount",
            "late_fee_amount",
            "is_bounced",
            "notes",
            "created_at",
        ]


class EnrollmentFeeSummarySerializer(serializers.Serializer):
    """Serializer for complete fee summary of an enrollment"""

    enrollment_id = (
        serializers.SerializerMethodField()
    )  # Changed to SerializerMethodField
    student_name = serializers.SerializerMethodField()
    student_id = serializers.SerializerMethodField()
    academic_class = serializers.SerializerMethodField()
    academic_term = serializers.SerializerMethodField()

    fee_breakdown = serializers.SerializerMethodField()
    payment_history = serializers.SerializerMethodField()

    total_fees = serializers.SerializerMethodField()
    total_paid = serializers.SerializerMethodField()
    total_balance = serializers.SerializerMethodField()
    total_overdue = serializers.SerializerMethodField()

    class Meta:
        fields = [
            "enrollment_id",
            "student_name",
            "student_id",
            "academic_class",
            "academic_term",
            "fee_breakdown",
            "payment_history",
            "total_fees",
            "total_paid",
            "total_balance",
            "total_overdue",
        ]

    def get_enrollment_id(self, obj):
        """Get enrollment ID from enrollment object"""
        return obj["enrollment"].id

    def get_student_name(self, obj):
        return (
            obj["enrollment"].student.full_name
            or f"{obj['enrollment'].student.first_name} {obj['enrollment'].student.last_name}".strip()
        )

    def get_student_id(self, obj):
        return obj["enrollment"].student.id

    def get_academic_class(self, obj):
        if obj["enrollment"].academic_class:
            academic_class = obj["enrollment"].academic_class

            # Get class name safely (since AcademicClass doesn't have a name field)
            class_name = str(academic_class)  # This uses the __str__ method

            return {
                "id": academic_class.id,
                "name": class_name,
                "standard": (
                    academic_class.standard.name if academic_class.standard else None
                ),
                "section": (
                    academic_class.section.name if academic_class.section else None
                ),
            }
        return None

    def get_academic_term(self, obj):
        # Get unique terms from fee assignments
        terms = set()
        for fee in obj["fee_assignments"]:
            if (
                hasattr(fee, "class_fee_structure")
                and fee.class_fee_structure
                and fee.class_fee_structure.academic_term
            ):
                term = fee.class_fee_structure.academic_term
                terms.add((term.id, term.name, term.start_date, term.end_date))
            elif (
                isinstance(fee, dict)
                and fee.get("class_fee_structure")
                and fee["class_fee_structure"].academic_term
            ):
                term = fee["class_fee_structure"].academic_term
                terms.add((term.id, term.name, term.start_date, term.end_date))

        return [
            {"id": t[0], "name": t[1], "start_date": t[2], "end_date": t[3]}
            for t in terms
        ]

    def get_fee_breakdown(self, obj):
        """Get detailed breakdown of all fees"""
        fee_details = []
        for fee_assignment in obj["fee_assignments"]:
            if isinstance(fee_assignment, dict):
                # Handle dict items (class structures without student assignment)
                fee_details.append(self._format_class_structure(fee_assignment))
            else:
                # Handle StudentFeeAssignment objects
                serializer = StudentFeeDetailSerializer(fee_assignment)
                fee_details.append(serializer.data)
        return fee_details

    def _format_class_structure(self, class_structure_dict):
        """Format a class structure dict to match StudentFeeDetailSerializer output"""
        class_fee = class_structure_dict.get("class_fee_structure")
        if not class_fee:
            return {}

        # Get fee component details
        fee_component = class_fee.fee_component
        fee_component_details = None
        if fee_component:
            fee_component_details = {
                "id": fee_component.id,
                "name": fee_component.name,
                "code": fee_component.code,
                "category_name": (
                    fee_component.category.name if fee_component.category else None
                ),
            }

        return {
            "fee_structure": {
                "id": class_fee.id,
                "fee_component": class_fee.fee_component_id,
                "fee_component_details": fee_component_details,
                "academic_term": class_fee.academic_term_id,
                "term_name": (
                    class_fee.academic_term.name if class_fee.academic_term else None
                ),
                "amount": class_fee.amount,
                "due_date": class_fee.due_date,
                "notes": class_fee.notes,
                "is_active": class_fee.is_active,
            },
            "student_assignment": {
                "id": None,  # No assignment ID for class-only fees
                "discount_type": None,
                "discount_value": None,
                "due_date_override": None,
                "is_active": True,
                "reason": None,
            },
            "effective_due_date": class_fee.due_date,
            "payment_status": "pending",
            "amount_paid": 0,
            "balance_due": class_fee.amount,
        }

    def get_payment_history(self, obj):
        """Get all payments for this enrollment"""
        payments = FeePayment.objects.filter(
            student_enrollment=obj["enrollment"], status="completed"
        ).order_by("-payment_date")
        return FeePaymentHistorySerializer(payments, many=True).data

    def get_total_fees(self, obj):
        """Calculate total fees for this enrollment"""
        total = 0
        for fee in obj["fee_assignments"]:
            if isinstance(fee, dict):
                class_fee = fee.get("class_fee_structure")
                if class_fee:
                    total += class_fee.amount
            else:
                total += fee.calculate_final_amount()
        return total

    def get_total_paid(self, obj):
        """Calculate total amount paid for this enrollment"""
        total = (
            FeePayment.objects.filter(
                student_enrollment=obj["enrollment"], status="completed"
            ).aggregate(total=models.Sum("amount_paid"))["total"]
            or 0
        )
        return total

    def get_total_balance(self, obj):
        """Calculate total balance due"""
        return self.get_total_fees(obj) - self.get_total_paid(obj)

    def get_total_overdue(self, obj):
        """Calculate total overdue amount"""
        today = timezone.now().date()
        overdue_total = 0

        for fee in obj["fee_assignments"]:
            if isinstance(fee, dict):
                class_fee = fee.get("class_fee_structure")
                if class_fee and class_fee.due_date and class_fee.due_date < today:
                    # Check if any payment exists for this class fee
                    has_payment = FeePayment.objects.filter(
                        student_enrollment=obj["enrollment"],
                        fee_assignments__class_fee_structure=class_fee,
                        status="completed",
                    ).exists()
                    if not has_payment:
                        overdue_total += class_fee.amount
            else:
                effective_due_date = (
                    fee.due_date_override or fee.class_fee_structure.due_date
                )
                if effective_due_date and effective_due_date < today:
                    payments = fee.payments.filter(status="completed")
                    total_paid = (
                        payments.aggregate(total=models.Sum("amount_paid"))["total"]
                        or 0
                    )
                    final_amount = fee.calculate_final_amount()
                    if total_paid < final_amount:
                        overdue_total += final_amount - total_paid

        return overdue_total


class AnnouncementTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = AnnouncementType
        fields = ["id", "name", "code", "description"]


class CommonAnnouncementSerializer(serializers.ModelSerializer):
    announcement_type_details = AnnouncementTypeSerializer(
        source="announcement_type", read_only=True
    )
    is_expired = serializers.SerializerMethodField()
    days_remaining = serializers.SerializerMethodField()
    formatted_created_at = serializers.SerializerMethodField()
    formatted_expire_on = serializers.SerializerMethodField()

    class Meta:
        model = CommonAnnouncement
        fields = [
            "id",
            "title",
            "message",
            "priority",
            "announcement_type",
            "announcement_type_details",
            "expire_on",
            "formatted_expire_on",
            "from_role",
            "created_at",
            "formatted_created_at",
            "is_expired",
            "days_remaining",
        ]

    def get_is_expired(self, obj):
        if obj.expire_on:
            return obj.expire_on < timezone.now().date()
        return False

    def get_days_remaining(self, obj):
        if obj.expire_on:
            today = timezone.now().date()
            if obj.expire_on >= today:
                return (obj.expire_on - today).days
        return None

    def get_formatted_created_at(self, obj):
        return obj.created_at.strftime("%b %d, %Y") if obj.created_at else None

    def get_formatted_expire_on(self, obj):
        return obj.expire_on.strftime("%b %d, %Y") if obj.expire_on else None


class StudentAnnouncementSerializer(serializers.ModelSerializer):
    announcement_type_details = AnnouncementTypeSerializer(
        source="announcement_type", read_only=True
    )
    is_expired = serializers.SerializerMethodField()
    days_remaining = serializers.SerializerMethodField()
    formatted_created_at = serializers.SerializerMethodField()
    formatted_expire_on = serializers.SerializerMethodField()
    target_audience = serializers.SerializerMethodField()
    class_details = serializers.SerializerMethodField()

    class Meta:
        model = StudentAnnouncement
        fields = [
            "id",
            "title",
            "message",
            "priority",
            "announcement_type",
            "announcement_type_details",
            "section",
            "academic_class",
            "is_for_all_students",
            "expire_on",
            "formatted_expire_on",
            "from_role",
            "created_at",
            "formatted_created_at",
            "is_expired",
            "days_remaining",
            "target_audience",
            "class_details",
        ]

    def get_is_expired(self, obj):
        if obj.expire_on:
            return obj.expire_on < timezone.now().date()
        return False

    def get_days_remaining(self, obj):
        if obj.expire_on:
            today = timezone.now().date()
            if obj.expire_on >= today:
                return (obj.expire_on - today).days
        return None

    def get_formatted_created_at(self, obj):
        return obj.created_at.strftime("%b %d, %Y") if obj.created_at else None

    def get_formatted_expire_on(self, obj):
        return obj.expire_on.strftime("%b %d, %Y") if obj.expire_on else None

    def get_target_audience(self, obj):
        if obj.is_for_all_students:
            return "All Students"
        elif obj.section:
            section_display = dict(StudentAnnouncement.SECTION_CHOICES).get(
                obj.section, obj.section
            )
            return f"Section: {section_display}"
        elif obj.academic_class:
            return f"Specific Class"
        return "Specific Students"

    def get_class_details(self, obj):
        """Get formatted class details if academic_class exists"""
        if obj.academic_class:
            try:
                standard_name = (
                    obj.academic_class.standard.name
                    if obj.academic_class.standard
                    else ""
                )
                section_name = (
                    obj.academic_class.section.name
                    if obj.academic_class.section
                    else ""
                )
                academic_year = (
                    obj.academic_class.academic_year.name
                    if obj.academic_class.academic_year
                    else ""
                )

                return {
                    "id": obj.academic_class.id,
                    "display_name": f"{standard_name} - {section_name}".strip(" -"),
                    "standard": standard_name,
                    "section": section_name,
                    "academic_year": academic_year,
                }
            except:
                return {
                    "id": obj.academic_class.id,
                    "display_name": "Class details unavailable",
                }
        return None


class StudentBasicAttendanceSerializer(serializers.ModelSerializer):
    """Basic student info for attendance"""

    full_name = serializers.SerializerMethodField()
    roll_number = serializers.IntegerField(source="enrollment.roll_number")
    enrollment_id = serializers.IntegerField(source="enrollment.id")

    class Meta:
        model = Student
        fields = ["id", "full_name", "admission_number", "roll_number", "enrollment_id"]

    def get_full_name(self, obj):
        return obj.full_name or f"{obj.first_name} {obj.last_name}".strip()


class AttendanceSessionBasicSerializer(serializers.ModelSerializer):
    """Basic attendance session info"""

    class_name = serializers.CharField(source="academic_class.__str__")
    weekday_name = serializers.CharField(source="weekday.day_name", allow_null=True)

    class Meta:
        model = AttendanceSession
        fields = [
            "id",
            "date",
            "session_type",
            "status",
            "class_name",
            "weekday_name",
            "total_students",
            "present_count",
            "absent_count",
            "late_count",
            "leave_count",
        ]


class ParentStudentAttendanceSerializer(serializers.ModelSerializer):
    """Serializer for student attendance records"""

    student_name = serializers.SerializerMethodField()
    roll_number = serializers.IntegerField(source="enrollment.roll_number")
    student_id = serializers.IntegerField(source="student.id")
    date = serializers.DateField(source="session.date")
    session_type = serializers.CharField(source="session.session_type")
    session_status = serializers.CharField(source="session.status")
    weekday_name = serializers.SerializerMethodField()

    class Meta:
        model = StudentAttendance
        fields = [
            "id",
            "student_id",
            "student_name",
            "roll_number",
            "date",
            "session_type",
            "session_status",
            "status",
            "remarks",
            "late_minutes",
            "marked_at",
            "weekday_name",
        ]

    def get_student_name(self, obj):
        return (
            obj.student.full_name
            or f"{obj.student.first_name} {obj.student.last_name}".strip()
        )

    def get_weekday_name(self, obj):
        if obj.session.date:
            weekday_names = [
                "Monday",
                "Tuesday",
                "Wednesday",
                "Thursday",
                "Friday",
                "Saturday",
                "Sunday",
            ]
            return weekday_names[obj.session.date.weekday()]
        return None


class ParentAttendanceOverviewSerializer(serializers.Serializer):
    """Serializer for attendance overview"""

    total_working_days = serializers.IntegerField()
    present_days = serializers.IntegerField()
    absent_days = serializers.IntegerField()
    late_days = serializers.IntegerField()
    leave_days = serializers.IntegerField()
    attendance_percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
    is_below_minimum = serializers.BooleanField()


class ParentMonthlyAttendanceSerializer(serializers.ModelSerializer):
    """Serializer for monthly attendance summary"""

    student_name = serializers.SerializerMethodField()
    roll_number = serializers.IntegerField(source="enrollment.roll_number")
    month_name = serializers.SerializerMethodField()

    class Meta:
        model = AttendanceSummary
        fields = [
            "id",
            "student_name",
            "roll_number",
            "month",
            "month_name",
            "year",
            "total_working_days",
            "present_days",
            "absent_days",
            "late_days",
            "leave_days",
            "half_days",
            "attendance_percentage",
            "is_below_minimum",
        ]

    def get_student_name(self, obj):
        return (
            obj.student.full_name
            or f"{obj.student.first_name} {obj.student.last_name}".strip()
        )

    def get_month_name(self, obj):
        months = [
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December",
        ]
        return months[obj.month - 1] if 1 <= obj.month <= 12 else str(obj.month)


class AttendanceCalendarDaySerializer(serializers.Serializer):
    """Serializer for single day in calendar"""

    date = serializers.DateField()
    weekday = serializers.CharField()
    status = serializers.CharField(allow_null=True)
    status_display = serializers.CharField(allow_null=True)
    is_holiday = serializers.BooleanField()
    holiday_name = serializers.CharField(allow_null=True)
    remarks = serializers.CharField(allow_null=True)
    late_minutes = serializers.IntegerField(allow_null=True)


class ParentAttendanceStatisticsSerializer(serializers.Serializer):
    """Serializer for attendance statistics"""

    period = serializers.CharField()
    present_percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
    absent_percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
    late_percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
    leave_percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
    trend = serializers.CharField(allow_null=True)


class ParentLeaveHistorySerializer(serializers.ModelSerializer):
    """Serializer for leave history"""

    student_name = serializers.SerializerMethodField()
    class_name = serializers.SerializerMethodField()
    leave_type_display = serializers.CharField(source="get_leave_type_display")
    status_display = serializers.CharField(source="get_status_display")
    total_days = serializers.IntegerField(read_only=True)

    class Meta:
        model = AttendanceLeave
        fields = [
            "id",
            "student_id",
            "student_name",
            "class_name",
            "leave_type",
            "leave_type_display",
            "from_date",
            "to_date",
            "total_days",
            "reason",
            "document",
            "status",
            "status_display",
            "approved_by",
            "approved_at",
            "rejection_reason",
            "created_at",
        ]

    def get_student_name(self, obj):
        return (
            obj.student.full_name
            or f"{obj.student.first_name} {obj.student.last_name}".strip()
        )

    def get_class_name(self, obj):
        if obj.enrollment and obj.enrollment.academic_class:
            standard = (
                obj.enrollment.academic_class.standard.name
                if obj.enrollment.academic_class.standard
                else ""
            )
            section = (
                obj.enrollment.academic_class.section.name
                if obj.enrollment.academic_class.section
                else ""
            )
            return f"{standard} - {section}".strip(" -")
        return None


class ParentLeaveDetailSerializer(ParentLeaveHistorySerializer):
    """Detailed serializer for leave details"""

    enrollment_details = serializers.SerializerMethodField()

    class Meta(ParentLeaveHistorySerializer.Meta):
        fields = ParentLeaveHistorySerializer.Meta.fields + ["enrollment_details"]

    def get_enrollment_details(self, obj):
        if obj.enrollment:
            return {
                "enrollment_id": obj.enrollment.id,
                "academic_year": (
                    obj.enrollment.academic_class.academic_year.name
                    if obj.enrollment.academic_class
                    else None
                ),
                "roll_number": obj.enrollment.roll_number,
            }
        return None


# =====================================================
# LEAVE REQUEST SERIALIZERS
# =====================================================


class ParentLeaveTypeSerializer(serializers.Serializer):
    """Serializer for leave types"""

    code = serializers.CharField()
    name = serializers.CharField()
    description = serializers.CharField()


class ParentLeaveRequestListSerializer(serializers.ModelSerializer):
    """Serializer for listing leave requests"""

    student_name = serializers.SerializerMethodField()
    class_name = serializers.SerializerMethodField()
    leave_type_display = serializers.CharField(source="get_leave_type_display")
    status_display = serializers.CharField(source="get_status_display")
    total_days = serializers.SerializerMethodField()
    document_url = serializers.SerializerMethodField()

    class Meta:
        model = AttendanceLeave
        fields = [
            "id",
            "student_id",
            "student_name",
            "class_name",
            "leave_type",
            "leave_type_display",
            "from_date",
            "to_date",
            "total_days",
            "reason",
            "document",
            "document_url",
            "status",
            "status_display",
            "rejection_reason",
            "created_at",
        ]

    def get_student_name(self, obj):
        return (
            obj.student.full_name
            or f"{obj.student.first_name} {obj.student.last_name}".strip()
        )

    def get_class_name(self, obj):
        if obj.enrollment and obj.enrollment.academic_class:
            standard = (
                obj.enrollment.academic_class.standard.name
                if obj.enrollment.academic_class.standard
                else ""
            )
            section = (
                obj.enrollment.academic_class.section.name
                if obj.enrollment.academic_class.section
                else ""
            )
            return f"{standard} - {section}".strip(" -")
        return None

    def get_total_days(self, obj):
        return (obj.to_date - obj.from_date).days + 1

    def get_document_url(self, obj):
        if obj.document:
            return obj.document.url
        return None


class ParentLeaveRequestCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating a new leave request"""

    class Meta:
        model = AttendanceLeave
        fields = [
            "enrollment_id",
            "leave_type",
            "from_date",
            "to_date",
            "reason",
            "document",
        ]

    def validate(self, data):
        """Validate leave request data"""
        from_date = data.get("from_date")
        to_date = data.get("to_date")

        # Check if dates are provided
        if not from_date or not to_date:
            raise serializers.ValidationError("Both from_date and to_date are required")

        # Check if from_date is not in the past
        if from_date < timezone.now().date():
            raise serializers.ValidationError("Leave start date cannot be in the past")

        # Check if to_date is after from_date
        if to_date < from_date:
            raise serializers.ValidationError("End date must be after start date")

        # Check if leave duration is within limits (e.g., max 30 days)
        days = (to_date - from_date).days + 1
        if days > 30:
            raise serializers.ValidationError("Leave cannot exceed 30 days")

        return data

    def validate_enrollment_id(self, value):
        """Validate that enrollment exists and is active"""
        from academics.models import StudentEnrollment

        try:
            enrollment = StudentEnrollment.objects.get(id=value, is_active=True)
            return value
        except StudentEnrollment.DoesNotExist:
            raise serializers.ValidationError(
                "Invalid enrollment ID or enrollment not active"
            )

    def validate_leave_type(self, value):
        """Validate leave type"""
        valid_types = ["MEDICAL", "FAMILY", "EMERGENCY", "SPORTS", "OTHER"]
        if value not in valid_types:
            raise serializers.ValidationError(
                f"Invalid leave type. Must be one of: {', '.join(valid_types)}"
            )
        return value


class ParentLeaveRequestDetailSerializer(ParentLeaveRequestListSerializer):
    """Detailed serializer for leave request with full details"""

    enrollment_details = serializers.SerializerMethodField()
    approved_by_name = serializers.SerializerMethodField()
    approved_at_formatted = serializers.SerializerMethodField()
    created_at_formatted = serializers.SerializerMethodField()

    class Meta(ParentLeaveRequestListSerializer.Meta):
        fields = ParentLeaveRequestListSerializer.Meta.fields + [
            "enrollment_details",
            "approved_by_name",
            "approved_at",
            "approved_at_formatted",
            "updated_at",
            "created_at_formatted",
        ]

    def get_enrollment_details(self, obj):
        if obj.enrollment:
            return {
                "enrollment_id": obj.enrollment.id,
                "roll_number": obj.enrollment.roll_number,
                "academic_year": (
                    obj.enrollment.academic_class.academic_year.name
                    if obj.enrollment.academic_class
                    else None
                ),
                "class_id": (
                    obj.enrollment.academic_class.id
                    if obj.enrollment.academic_class
                    else None
                ),
            }
        return None

    def get_approved_by_name(self, obj):
        if obj.approved_by:
            return f"{obj.approved_by.first_name} {obj.approved_by.last_name}".strip()
        return None

    def get_approved_at_formatted(self, obj):
        if obj.approved_at:
            return obj.approved_at.strftime("%d %b %Y, %H:%M")
        return None

    def get_created_at_formatted(self, obj):
        return obj.created_at.strftime("%d %b %Y, %H:%M")


class ParentLeaveRequestUpdateSerializer(serializers.ModelSerializer):
    """Serializer for updating a leave request (only if still pending)"""

    class Meta:
        model = AttendanceLeave
        fields = ["leave_type", "from_date", "to_date", "reason", "document"]

    def validate(self, data):
        from_date = data.get("from_date")
        to_date = data.get("to_date")

        if from_date and to_date:
            if from_date < timezone.now().date():
                raise serializers.ValidationError(
                    "Leave start date cannot be in the past"
                )
            if to_date < from_date:
                raise serializers.ValidationError("End date must be after start date")

            days = (to_date - from_date).days + 1
            if days > 30:
                raise serializers.ValidationError("Leave cannot exceed 30 days")

        return data


class TransportTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = TransportType
        fields = ["id", "name"]


class TransportVehicleSerializer(serializers.ModelSerializer):
    transport_type_name = serializers.CharField(
        source="transport_type.name", read_only=True
    )

    class Meta:
        model = TransportVehicle
        fields = [
            "id",
            "transport_type",
            "transport_type_name",
            "vehicle_number",
            "bus_number",
            "driver_name",
            "driver_phone",
            "capacity",
            "vehicle_photo",
        ]


class TransportVehicleDetailSerializer(serializers.ModelSerializer):
    transport_type = TransportTypeSerializer(read_only=True)
    current_occupancy = serializers.SerializerMethodField()
    available_seats = serializers.SerializerMethodField()

    class Meta:
        model = TransportVehicle
        fields = [
            "id",
            "transport_type",
            "vehicle_number",
            "bus_number",
            "driver_name",
            "driver_phone",
            "capacity",
            "vehicle_photo",
            "current_occupancy",
            "available_seats",
        ]

    def get_current_occupancy(self, obj):
        return StudentTransport.objects.filter(vehicle=obj, is_active=True).count()

    def get_available_seats(self, obj):
        occupied = self.get_current_occupancy(obj)
        return obj.capacity - occupied


class StopSerializer(serializers.ModelSerializer):
    class Meta:
        model = Stop
        fields = ["id", "stop_name", "stop_order", "arrival_time"]


class RouteSerializer(serializers.ModelSerializer):
    vehicle_info = TransportVehicleSerializer(source="vehicle", read_only=True)
    stops = StopSerializer(many=True, read_only=True)
    total_stops = serializers.SerializerMethodField()

    class Meta:
        model = Route
        fields = [
            "id",
            "vehicle",
            "vehicle_info",
            "route_name",
            "start_location",
            "destination",
            "distance_km",
            "stops",
            "total_stops",
        ]

    def get_total_stops(self, obj):
        return obj.stops.count()


class RouteDetailSerializer(serializers.ModelSerializer):
    vehicle = TransportVehicleDetailSerializer(read_only=True)
    stops = StopSerializer(many=True, read_only=True)

    class Meta:
        model = Route
        fields = "__all__"


class StudentTransportSerializer(serializers.ModelSerializer):
    student_name = serializers.CharField(source="student.full_name", read_only=True)
    student_id = serializers.IntegerField(source="student.id", read_only=True)
    vehicle_number = serializers.CharField(source="vehicle.bus_number", read_only=True)
    route_name = serializers.CharField(source="route.route_name", read_only=True)
    stop_name = serializers.CharField(
        source="stop.stop_name", read_only=True, allow_null=True
    )
    enrollment_info = StudentEnrollmentSerializer(source="enrollment", read_only=True)

    class Meta:
        model = StudentTransport
        fields = [
            "id",
            "student",
            "student_name",
            "student_id",
            "enrollment",
            "enrollment_info",
            "enrollment_number",
            "vehicle",
            "vehicle_number",
            "route",
            "route_name",
            "stop",
            "stop_name",
            "pickup_point",
            "fee_amount",
            "is_active",
            "academic_year",
        ]


class StudentTransportDetailSerializer(serializers.ModelSerializer):
    student = StudentSerializer(read_only=True)
    vehicle = TransportVehicleDetailSerializer(read_only=True)
    route = RouteSerializer(read_only=True)
    stop = StopSerializer(read_only=True)
    enrollment = StudentEnrollmentSerializer(read_only=True)

    class Meta:
        model = StudentTransport
        fields = "__all__"


class StudentCurrentTransportSerializer(serializers.Serializer):
    """Serializer for current transport details of a student"""

    has_transport = serializers.BooleanField()
    transport_details = StudentTransportSerializer(allow_null=True)
    message = serializers.CharField(allow_null=True, allow_blank=True)

class ExamTypeSerializer(serializers.ModelSerializer):
    """Serializer for exam type information"""
    class Meta:
        model = ExamType
        fields = [
            'id', 'name', 'code', 'is_terminal', 'is_mid_term',
            'is_continuous_assessment', 'grading_system', 'max_marks', 
            'passing_marks'
        ]


class ExamSubjectSerializer(serializers.ModelSerializer):
    """Serializer for exam subjects with timing details"""
    subject_name = serializers.CharField(source='subject.name', read_only=True)
    subject_code = serializers.CharField(source='subject.code', read_only=True)
    end_time = serializers.SerializerMethodField()
    invigilators_list = serializers.SerializerMethodField()
    
    class Meta:
        model =ExamSubject
        fields = [
            'id', 'subject', 'subject_name', 'subject_code',
            'max_marks', 'passing_marks', 'exam_date', 
            'start_time', 'duration_minutes', 'end_time',
            'room_number', 'invigilators_list', 'teacher_in_charge',
            'extra_instructions'
        ]
    
    def get_end_time(self, obj):
        return obj.end_time
    
    def get_invigilators_list(self, obj):
        invigilators = obj.invigilators.all()
        return [
            {
                'id': inv.id,
                'name': f"{inv.first_name} {inv.last_name}".strip()
            }
            for inv in invigilators
        ]


class ExamSubjectMinimalSerializer(serializers.ModelSerializer):
    """Minimal serializer for exam subjects list"""
    subject_name = serializers.CharField(source='subject.name', read_only=True)
    subject_code = serializers.CharField(source='subject.code', read_only=True)
    
    class Meta:
        model = ExamSubject
        fields = [
            'id', 'subject', 'subject_name', 'subject_code',
            'exam_date', 'start_time', 'duration_minutes'
        ]


class StudentMarksSerializer(serializers.ModelSerializer):
    """Serializer for student marks in a subject"""
    subject_name = serializers.CharField(source='exam_subject.subject.name', read_only=True)
    subject_code = serializers.CharField(source='exam_subject.subject.code', read_only=True)
    max_marks = serializers.DecimalField(source='exam_subject.max_marks', decimal_places=2, max_digits=6, read_only=True)
    passing_marks = serializers.DecimalField(source='exam_subject.passing_marks', decimal_places=2, max_digits=6, read_only=True)
    percentage = serializers.SerializerMethodField()
    is_passed = serializers.SerializerMethodField()
    
    class Meta:
        model = StudentMarks
        fields = [
            'id', 'exam_subject_id', 'subject_name', 'subject_code',
            'obtained_marks', 'max_marks', 'passing_marks', 
            'percentage', 'is_passed', 'grade', 'grade_point',
            'is_absent', 'is_withheld', 'remarks'
        ]
    
    def get_percentage(self, obj):
        return obj.percentage
    
    def get_is_passed(self, obj):
        return obj.is_passed


class ExamResultSerializer(serializers.ModelSerializer):
    """Serializer for consolidated exam results"""
    student_name = serializers.CharField(source='student_enrollment.student.full_name', read_only=True)
    roll_number = serializers.IntegerField(source='student_enrollment.roll_number', read_only=True)
    class_name = serializers.SerializerMethodField()
    
    class Meta:
        model = ExamResult
        fields = [
            'id', 'student_name', 'roll_number', 'class_name',
            'total_marks', 'total_max_marks', 'percentage',
            'overall_grade', 'overall_grade_point', 'result_status',
            'rank', 'remarks'
        ]
    
    def get_class_name(self, obj):
        if obj.student_enrollment and obj.student_enrollment.academic_class:
            return str(obj.student_enrollment.academic_class)
        return None


class ExamListSerializer(serializers.ModelSerializer):
    """Serializer for listing exams (upcoming/past)"""
    exam_type_name = serializers.CharField(source='exam_type.name', read_only=True)
    exam_type_code = serializers.CharField(source='exam_type.code', read_only=True)
    is_results_published = serializers.BooleanField(read_only=True)
    subjects_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Exam
        fields = [
            'id', 'name', 'code', 'exam_type', 'exam_type_name', 
            'exam_type_code', 'start_date', 'end_date', 'status',
            'is_results_published', 'weightage', 'subjects_count'
        ]
    
    def get_subjects_count(self, obj):
        return obj.exam_subjects.filter(is_active=True).count()


class ExamDetailSerializer(serializers.ModelSerializer):
    """Detailed serializer for a single exam with subjects"""
    exam_type = ExamTypeSerializer(read_only=True)
    exam_type_id = serializers.IntegerField(write_only=True, required=False)
    academic_class_name = serializers.CharField(source='academic_class.__str__', read_only=True)
    academic_year_name = serializers.CharField(source='academic_year.name', read_only=True)
    subjects = serializers.SerializerMethodField()
    is_results_published = serializers.BooleanField(read_only=True)
    duration_days = serializers.IntegerField(read_only=True)
    total_registered_students = serializers.IntegerField(read_only=True)
    total_eligible_students = serializers.IntegerField(read_only=True)
    
    class Meta:
        model = Exam
        fields = [
            'id', 'name', 'code', 'exam_type', 'exam_type_id',
            'academic_class', 'academic_class_name',
            'academic_year', 'academic_year_name',
            'start_date', 'end_date', 'status', 'weightage',
            'is_results_published', 'instructions', 'duration_days',
            'total_registered_students', 'total_eligible_students',
            'subjects', 'created_at'
        ]
    
    def get_subjects(self, obj):
        subjects = obj.exam_subjects.filter(is_active=True).order_by('exam_date', 'start_time')
        return ExamSubjectSerializer(subjects, many=True, context=self.context).data


class StudentExamResultDetailSerializer(serializers.Serializer):
    """Serializer for complete exam result with subject-wise marks"""
    exam_info = ExamDetailSerializer()
    result_summary = ExamResultSerializer()
    subject_marks = StudentMarksSerializer(many=True)
    
    class Meta:
        fields = ['exam_info', 'result_summary', 'subject_marks']


class UpcomingExamsResponseSerializer(serializers.Serializer):
    """Response serializer for upcoming exams"""
    upcoming_exams = ExamListSerializer(many=True)
    ongoing_exams = ExamListSerializer(many=True)
    total_upcoming = serializers.IntegerField()
    total_ongoing = serializers.IntegerField()


class PastExamsResponseSerializer(serializers.Serializer):
    """Response serializer for past exams"""
    completed_exams = ExamListSerializer(many=True)
    results_published_exams = ExamListSerializer(many=True)
    total_completed = serializers.IntegerField()
    total_results_published = serializers.IntegerField()


class ExamRegistrationStatusSerializer(serializers.ModelSerializer):
    """Serializer for student exam registration status"""
    exam_name = serializers.CharField(source='exam.name', read_only=True)
    exam_code = serializers.CharField(source='exam.code', read_only=True)
    exam_start_date = serializers.DateField(source='exam.start_date', read_only=True)
    exam_end_date = serializers.DateField(source='exam.end_date', read_only=True)
    exam_status = serializers.CharField(source='exam.status', read_only=True)
    hall_ticket_number = serializers.CharField()
    seat_number = serializers.CharField()
    
    class Meta:
        model = StudentExamRegistration
        fields = [
            'id', 'exam', 'exam_name', 'exam_code', 'exam_start_date',
            'exam_end_date', 'exam_status', 'is_registered', 
            'hall_ticket_number', 'seat_number', 'registration_date',
            'needs_special_accommodation', 'accommodation_details'
        ]


class AIParentAssistantSerializer(serializers.Serializer):
    question = serializers.CharField(max_length=500)
    enrollment_id = serializers.IntegerField()
    academic_year_id = serializers.IntegerField(required=False, allow_null=True)