from rest_framework import serializers
from exam.models import ClassTest, ClassTestStudent
from academics.models import AcademicClass, Subject, SubjectTeacher, StudentEnrollment
from people.models import Student
from schedules.models import TimeTable


class AvailablePeriodSerializer(serializers.ModelSerializer):
    class_name = serializers.SerializerMethodField()
    subject_name = serializers.SerializerMethodField()
    subject_id = serializers.SerializerMethodField()
    subject_teacher_id = serializers.IntegerField(source="subject_teacher_id")

    class Meta:
        model = TimeTable
        fields = [
            "id",
            "academic_class",
            "class_name",
            "subject_id",
            "subject_name",
            "subject_teacher_id",
            "period_number",
            "start_time",
            "end_time",
            "room_number",
        ]

    def get_class_name(self, obj):
        if obj.academic_class:
            return str(obj.academic_class)
        return None

    def get_subject_name(self, obj):
        if obj.subject:
            return obj.subject.name
        return None

    def get_subject_id(self, obj):
        return obj.subject_id


class ClassTestCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ClassTest
        fields = [
            "id",
            "title",
            "test_type",
            "academic_year",
            "academic_class",
            "subject",
            "subject_teacher",
            "timetable_period",
            "test_date",
            "period_number",
            "start_time",
            "end_time",
            "max_marks",
            "passing_marks",
            "duration_minutes",
            "description",
        ]

    def validate(self, data):
        teacher = self.context["teacher"]
        academic_class = data.get("academic_class")
        subject = data.get("subject")
        subject_teacher = data.get("subject_teacher")

        if subject:
            # Subject teacher must own this subject+class combination
            if not subject_teacher:
                st = SubjectTeacher.objects.filter(
                    teacher=teacher, academic_class=academic_class, subject=subject
                ).first()
                if not st:
                    raise serializers.ValidationError(
                        "You are not assigned as subject teacher for this subject in this class."
                    )
                data["subject_teacher"] = st
            else:
                if subject_teacher.teacher != teacher:
                    raise serializers.ValidationError(
                        "Subject teacher record does not belong to you."
                    )
        else:
            # Class teacher test — teacher must be class_teacher of this class
            if academic_class.class_teacher != teacher:
                raise serializers.ValidationError(
                    "You are not the class teacher for this class. "
                    "Only subject teachers can create subject-specific tests."
                )

        passing = data.get("passing_marks")
        max_marks = data.get("max_marks")
        if passing and max_marks and passing > max_marks:
            raise serializers.ValidationError(
                "Passing marks cannot exceed max marks."
            )

        return data


class ClassTestStudentSerializer(serializers.ModelSerializer):
    student_id = serializers.IntegerField(source="student_enrollment.student.id", read_only=True)
    student_name = serializers.SerializerMethodField()
    roll_number = serializers.CharField(source="student_enrollment.roll_number", read_only=True)
    admission_number = serializers.CharField(
        source="student_enrollment.student.admission_number", read_only=True
    )
    percentage = serializers.FloatField(read_only=True)
    is_passed = serializers.BooleanField(read_only=True)

    class Meta:
        model = ClassTestStudent
        fields = [
            "id",
            "student_enrollment",
            "student_id",
            "student_name",
            "roll_number",
            "admission_number",
            "is_absent",
            "marks_obtained",
            "remarks",
            "marks_entered_by",
            "marks_entered_at",
            "percentage",
            "is_passed",
        ]
        read_only_fields = ["marks_entered_by", "marks_entered_at"]

    def get_student_name(self, obj):
        s = obj.student_enrollment.student
        return f"{s.first_name} {s.last_name}".strip()


class ClassTestListSerializer(serializers.ModelSerializer):
    class_name = serializers.SerializerMethodField()
    subject_name = serializers.SerializerMethodField()
    total_students = serializers.SerializerMethodField()
    marks_entered_count = serializers.SerializerMethodField()

    class Meta:
        model = ClassTest
        fields = [
            "id",
            "title",
            "test_type",
            "academic_class",
            "class_name",
            "subject",
            "subject_name",
            "test_date",
            "period_number",
            "start_time",
            "end_time",
            "max_marks",
            "passing_marks",
            "status",
            "total_students",
            "marks_entered_count",
            "created_at",
        ]

    def get_class_name(self, obj):
        return str(obj.academic_class)

    def get_subject_name(self, obj):
        return obj.subject.name if obj.subject else None

    def get_total_students(self, obj):
        return obj.student_results.count()

    def get_marks_entered_count(self, obj):
        return obj.student_results.filter(marks_obtained__isnull=False).count()


class ClassTestDetailSerializer(serializers.ModelSerializer):
    class_name = serializers.SerializerMethodField()
    subject_name = serializers.SerializerMethodField()
    academic_year_name = serializers.CharField(source="academic_year.__str__", read_only=True)
    created_by_name = serializers.SerializerMethodField()
    student_results = ClassTestStudentSerializer(many=True, read_only=True)

    class Meta:
        model = ClassTest
        fields = [
            "id",
            "title",
            "test_type",
            "academic_year",
            "academic_year_name",
            "academic_class",
            "class_name",
            "subject",
            "subject_name",
            "subject_teacher",
            "timetable_period",
            "test_date",
            "period_number",
            "start_time",
            "end_time",
            "max_marks",
            "passing_marks",
            "duration_minutes",
            "description",
            "status",
            "created_by",
            "created_by_name",
            "created_at",
            "updated_at",
            "student_results",
        ]

    def get_class_name(self, obj):
        return str(obj.academic_class)

    def get_subject_name(self, obj):
        return obj.subject.name if obj.subject else None

    def get_created_by_name(self, obj):
        t = obj.created_by
        return f"{t.first_name} {t.last_name}".strip()


class BulkMarksEntrySerializer(serializers.Serializer):
    student_enrollment = serializers.IntegerField()
    marks_obtained = serializers.DecimalField(
        max_digits=6, decimal_places=2, required=False, allow_null=True
    )
    is_absent = serializers.BooleanField(default=False)
    remarks = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")

    def validate(self, data):
        if not data.get("is_absent") and data.get("marks_obtained") is None:
            raise serializers.ValidationError(
                "marks_obtained is required when student is not absent."
            )
        return data
