from rest_framework import serializers
from django.db import models
from django.utils import timezone
from .models import (
    ExamType,
    Exam,
    ExamClassRegistration,
    StudentExamRegistration,
    ExamSubject,
    StudentMarks,
    ExamResult,
    ExamAttendance,
    ExamGradeSystem,
    ExamConfiguration,
)
from academics.models import StudentEnrollment, AcademicClass, Subject


class ExamTypeSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Type CRUD operations
    """

    academic_term_name = serializers.CharField(
        source="academic_term.name", read_only=True, allow_null=True
    )

    class Meta:
        model = ExamType
        fields = [
            "id",
            "name",
            "code",
            "is_terminal",
            "is_mid_term",
            "is_continuous_assessment",
            "default_weightage",
            "grading_system",
            "max_marks",
            "passing_marks",
            "academic_term",
            "academic_term_name",
            "is_active",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ExamSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam CRUD operations
    """

    exam_type_name = serializers.CharField(source="exam_type.name", read_only=True)
    academic_year_name = serializers.CharField(
        source="academic_year.name", read_only=True
    )
    academic_class_name = serializers.CharField(
        source="academic_class.__str__", read_only=True
    )
    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)
    marks_entry_status = serializers.DictField(read_only=True)

    class Meta:
        model = Exam
        fields = [
            "id",
            "name",
            "code",
            "exam_type",
            "exam_type_name",
            "academic_year",
            "academic_year_name",
            "academic_class",
            "academic_class_name",
            "start_date",
            "end_date",
            "weightage",
            "status",
            "results_published_date",
            "instructions",
            "is_active",
            "created_at",
            "updated_at",
            "is_results_published",
            "duration_days",
            "total_registered_students",
            "total_eligible_students",
            "marks_entry_status",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ExamClassRegistrationSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Class Registration
    """

    exam_name = serializers.CharField(source="exam.name", read_only=True)
    academic_class_name = serializers.CharField(
        source="academic_class.__str__", read_only=True
    )
    registered_by_name = serializers.CharField(
        source="registered_by.get_full_name", read_only=True, allow_null=True
    )

    class Meta:
        model = ExamClassRegistration
        fields = [
            "id",
            "exam",
            "exam_name",
            "academic_class",
            "academic_class_name",
            "registration_date",
            "registered_by",
            "registered_by_name",
            "hall_ticket_prefix",
            "seat_number_prefix",
            "is_registered",
            "auto_generate_hall_tickets",
            "auto_generate_seat_numbers",
            "notes",
        ]
        read_only_fields = ["id", "registration_date"]


class StudentExamRegistrationSerializer(serializers.ModelSerializer):
    """
    Serializer for Student Exam Registration (list view)
    """

    student_name = serializers.SerializerMethodField()
    student_roll_number = serializers.IntegerField(
        source="student_enrollment.roll_number", read_only=True
    )
    class_name = serializers.CharField(
        source="student_enrollment.academic_class.__str__", read_only=True
    )
    exam_name = serializers.CharField(source="exam.name", read_only=True)
    registration_type_display = serializers.CharField(
        source="get_registration_type_display", read_only=True
    )
    hall_ticket_number = serializers.CharField(read_only=True)
    seat_number = serializers.CharField(read_only=True)

    class Meta:
        model = StudentExamRegistration
        fields = [
            "id",
            "student_enrollment",
            "student_name",
            "student_roll_number",
            "class_name",
            "exam",
            "exam_name",
            "class_registration",
            "registration_date",
            "registration_type",
            "registration_type_display",
            "is_registered",
            "hall_ticket_number",
            "seat_number",
            "needs_special_accommodation",
            "accommodation_details",
            "registered_by",
            "notes",
        ]
        read_only_fields = [
            "id",
            "registration_date",
            "hall_ticket_number",
            "seat_number",
        ]

    def get_student_name(self, obj):
        if obj.student_enrollment and obj.student_enrollment.student:
            first = obj.student_enrollment.student.first_name or ""
            last = obj.student_enrollment.student.last_name or ""
            return f"{first} {last}".strip()
        return None


class StudentExamRegistrationCreateUpdateSerializer(serializers.ModelSerializer):
    """
    Serializer for creating and updating student exam registrations
    """

    class Meta:
        model = StudentExamRegistration
        fields = [
            "id",
            "student_enrollment",
            "exam",
            "class_registration",
            "registration_type",
            "is_registered",
            "hall_ticket_number",
            "seat_number",
            "needs_special_accommodation",
            "accommodation_details",
            "registered_by",
            "notes",
        ]

    def validate(self, data):
        # Check if student is already registered for this exam
        exam = data.get("exam")
        student_enrollment = data.get("student_enrollment")

        if exam and student_enrollment:
            existing = StudentExamRegistration.objects.filter(
                student_enrollment=student_enrollment, exam=exam
            ).exclude(id=self.instance.id if self.instance else None)

            if existing.exists():
                raise serializers.ValidationError(
                    {
                        "student_enrollment": "Student is already registered for this exam"
                    }
                )

        # Check if student belongs to the exam's class
        if exam and student_enrollment:
            if student_enrollment.academic_class != exam.academic_class:
                raise serializers.ValidationError(
                    {
                        "student_enrollment": "Student is not enrolled in the exam's class"
                    }
                )

        return data

    def create(self, validated_data):
        # Auto-generate hall ticket if not provided
        if not validated_data.get("hall_ticket_number"):
            exam = validated_data.get("exam")
            student_enrollment = validated_data.get("student_enrollment")
            prefix = f"HT-{exam.academic_year.code}-{exam.code}"
            validated_data["hall_ticket_number"] = (
                f"{prefix}-{student_enrollment.roll_number}"
            )

        return super().create(validated_data)


# In exams/serializers.py


class ExamSubjectSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Subject
    """

    subject_name = serializers.CharField(source="subject.name", read_only=True)
    subject_code = serializers.CharField(source="subject.code", read_only=True)
    exam_name = serializers.CharField(source="exam.name", read_only=True)
    teacher_in_charge_name = serializers.SerializerMethodField()
    invigilators_names = serializers.SerializerMethodField()
    end_time = serializers.TimeField(read_only=True)

    class Meta:
        model = ExamSubject
        fields = [
            "id",
            "exam",
            "exam_name",
            "subject",
            "subject_name",
            "subject_code",
            "max_marks",
            "passing_marks",
            "exam_date",
            "start_time",
            "duration_minutes",
            "end_time",
            "room_number",
            "invigilators",
            "invigilators_names",
            "teacher_in_charge",
            "teacher_in_charge_name",
            "extra_instructions",
            "is_active",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_teacher_in_charge_name(self, obj):
        """Get teacher in charge full name safely"""
        if obj.teacher_in_charge:
            first_name = obj.teacher_in_charge.first_name or ""
            last_name = obj.teacher_in_charge.last_name or ""
            return f"{first_name} {last_name}".strip() or str(obj.teacher_in_charge)
        return None

    def get_invigilators_names(self, obj):
        """Get invigilators names safely"""
        names = []
        for teacher in obj.invigilators.all():
            first_name = teacher.first_name or ""
            last_name = teacher.last_name or ""
            full_name = f"{first_name} {last_name}".strip()
            names.append(full_name or str(teacher))
        return names


class StudentMarksSerializer(serializers.ModelSerializer):
    """
    Serializer for Student Marks
    """

    student_name = serializers.SerializerMethodField()
    student_roll_number = serializers.IntegerField(
        source="student_enrollment.roll_number", read_only=True
    )
    subject_name = serializers.CharField(
        source="exam_subject.subject.name", read_only=True
    )
    exam_name = serializers.CharField(source="exam_subject.exam.name", read_only=True)
    max_marks_display = serializers.IntegerField(
        source="exam_subject.max_marks", read_only=True
    )
    passing_marks_display = serializers.IntegerField(
        source="exam_subject.passing_marks", read_only=True
    )
    is_passed = serializers.BooleanField(read_only=True)
    percentage = serializers.DecimalField(
        read_only=True, max_digits=5, decimal_places=2
    )
    entered_by_name = serializers.CharField(
        source="entered_by.get_full_name", read_only=True, allow_null=True
    )

    class Meta:
        model = StudentMarks
        fields = [
            "id",
            "student_enrollment",
            "student_name",
            "student_roll_number",
            "exam_subject",
            "subject_name",
            "exam_name",
            "obtained_marks",
            "max_marks_display",
            "passing_marks_display",
            "grade",
            "grade_point",
            "is_absent",
            "is_withheld",
            "is_revaluation_applied",
            "entered_by",
            "entered_by_name",
            "entry_date",
            "last_updated",
            "revaluation_marks",
            "revaluation_reason",
            "revaluation_date",
            "remarks",
            "is_passed",
            "percentage",
        ]
        read_only_fields = ["id", "entry_date", "last_updated"]


class StudentMarksCreateUpdateSerializer(serializers.ModelSerializer):
    """
    Serializer for creating and updating student marks
    """

    class Meta:
        model = StudentMarks
        fields = [
            "id",
            "student_enrollment",
            "exam_subject",
            "obtained_marks",
            "grade",
            "grade_point",
            "is_absent",
            "is_withheld",
            "is_revaluation_applied",
            "entered_by",
            "revaluation_marks",
            "revaluation_reason",
            "revaluation_date",
            "remarks",
        ]

    def validate(self, data):
        exam_subject = data.get("exam_subject")
        obtained_marks = data.get("obtained_marks")

        if exam_subject and obtained_marks is not None:
            if obtained_marks > exam_subject.max_marks:
                raise serializers.ValidationError(
                    {"obtained_marks": f"Marks cannot exceed {exam_subject.max_marks}"}
                )

            if obtained_marks < 0:
                raise serializers.ValidationError(
                    {"obtained_marks": "Marks cannot be negative"}
                )

        return data


class ExamResultSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Result
    """

    student_name = serializers.SerializerMethodField()
    student_roll_number = serializers.IntegerField(
        source="student_enrollment.roll_number", read_only=True
    )
    class_name = serializers.CharField(
        source="student_enrollment.academic_class.__str__", read_only=True
    )
    exam_name = serializers.CharField(source="exam.name", read_only=True)

    class Meta:
        model = ExamResult
        fields = [
            "id",
            "student_enrollment",
            "student_name",
            "student_roll_number",
            "class_name",
            "exam",
            "exam_name",
            "total_marks",
            "total_max_marks",
            "percentage",
            "overall_grade",
            "overall_grade_point",
            "result_status",
            "rank",
            "remarks",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class ExamAttendanceSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Attendance
    """

    student_name = serializers.SerializerMethodField()
    student_roll_number = serializers.IntegerField(
        source="student_enrollment.roll_number", read_only=True
    )
    subject_name = serializers.CharField(
        source="exam_subject.subject.name", read_only=True
    )
    exam_name = serializers.CharField(source="exam_subject.exam.name", read_only=True)
    marked_by_name = serializers.CharField(
        source="marked_by.get_full_name", read_only=True, allow_null=True
    )

    class Meta:
        model = ExamAttendance
        fields = [
            "id",
            "student_enrollment",
            "student_name",
            "student_roll_number",
            "exam_subject",
            "subject_name",
            "exam_name",
            "is_present",
            "arrival_time",
            "departure_time",
            "is_late",
            "late_minutes",
            "early_departure_minutes",
            "remarks",
            "marked_by",
            "marked_by_name",
            "marked_at",
        ]
        read_only_fields = ["id", "marked_at"]


class ExamGradeSystemSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Grade System
    """

    class Meta:
        model = ExamGradeSystem
        fields = [
            "id",
            "name",
            "description",
            "grade_ranges",
            "is_active",
            "created_at",
        ]
        read_only_fields = ["id", "created_at"]


class ExamConfigurationSerializer(serializers.ModelSerializer):
    """
    Serializer for Exam Configuration
    """

    academic_year_name = serializers.CharField(
        source="academic_year.name", read_only=True
    )
    default_grade_system_name = serializers.CharField(
        source="default_grade_system.name", read_only=True, allow_null=True
    )

    class Meta:
        model = ExamConfiguration
        fields = [
            "id",
            "academic_year",
            "academic_year_name",
            "default_grade_system",
            "default_grade_system_name",
            "promotion_min_percentage",
            "max_subjects_fail_allowed",
            "allow_mark_entry_before_exam",
            "allow_mark_entry_after_results_published",
            "enable_grade_points",
            "enable_rank_calculation",
            "auto_register_students_on_exam_creation",
            "allow_student_self_registration",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


# =====================================================
# DASHBOARD & REPORTING SERIALIZERS
# =====================================================


class ExamDashboardStatsSerializer(serializers.Serializer):
    total_exams = serializers.IntegerField()
    ongoing_exams = serializers.IntegerField()
    scheduled_exams = serializers.IntegerField()
    completed_exams = serializers.IntegerField()
    results_published = serializers.IntegerField()
    total_students_registered = serializers.IntegerField()
    total_marks_entries = serializers.IntegerField()
    exams_by_type = serializers.DictField()
    exams_by_class = serializers.DictField()


class ExamPerformanceReportSerializer(serializers.Serializer):
    exam_id = serializers.IntegerField()
    exam_name = serializers.CharField()
    academic_class = serializers.CharField()
    total_students = serializers.IntegerField()
    total_appeared = serializers.IntegerField()
    total_passed = serializers.IntegerField()
    total_failed = serializers.IntegerField()
    pass_percentage = serializers.FloatField()
    average_percentage = serializers.FloatField()
    highest_percentage = serializers.FloatField()
    lowest_percentage = serializers.FloatField()
    subject_wise_breakdown = serializers.ListField()


class SubjectPerformanceSerializer(serializers.Serializer):
    subject_name = serializers.CharField()
    max_marks = serializers.IntegerField()
    average_marks = serializers.FloatField()
    highest_marks = serializers.FloatField()
    lowest_marks = serializers.FloatField()
    pass_percentage = serializers.FloatField()
    total_appeared = serializers.IntegerField()
    total_passed = serializers.IntegerField()
    total_failed = serializers.IntegerField()


class TopperListSerializer(serializers.Serializer):
    rank = serializers.IntegerField()
    student_name = serializers.CharField()
    roll_number = serializers.IntegerField()
    total_marks = serializers.DecimalField(max_digits=8, decimal_places=2)
    percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
    grade = serializers.CharField()
