# api/serializers.py

from rest_framework import serializers
from .models import CustomUser, QuizAttempt, Attendance, Quiz, LearningArea, LearningContent, ContentProgress, TeacherAllocation, ClassStream, Grade, Question, Option

# api/serializers.py (updated UserSerializer to include username for learners)

class UserSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()
    createdAt = serializers.SerializerMethodField()
    class_stream = serializers.SerializerMethodField()
    grade = serializers.SerializerMethodField()  # ← SerializerMethodField for grade
    parentId = serializers.ReadOnlyField(source='parent.id')
    parent = serializers.SerializerMethodField()
    children = serializers.SerializerMethodField()
    is_active = serializers.BooleanField()  # Added to include is_active status
    username = serializers.CharField(read_only=True)  # ← ADD THIS: Include username (admission for learners)

    class Meta:
        model = CustomUser
        fields = [
            'id', 'name', 'username', 'first_name', 'last_name', 'email', 'role',
            'createdAt', 'phone', 'class_stream', 'grade', 'parentId', 'parent',
            'children', 'is_active'
        ]  # ← ADD 'username' here

    def get_name(self, obj):
        full = f"{obj.first_name} {obj.last_name}".strip()
        return full if full else obj.email

    def get_createdAt(self, obj):
        return obj.date_joined.isoformat() if obj.date_joined else None

    def get_class_stream(self, obj):
        if obj.class_stream:
            return {
                'id': obj.class_stream.id,
                'name': f"{obj.class_stream.grade.name} - {obj.class_stream.stream_name}"
            }
        return None

    def get_grade(self, obj):
        if obj.role.lower() == 'learner' and obj.grade_level:
            try:
                g = Grade.objects.get(code=obj.grade_level)
                return g.name
            except Grade.DoesNotExist:
                return obj.grade_level  # Fallback to raw code
        return None

    def get_parent(self, obj):
        if obj.parent:
            return {
                'id': obj.parent.id,
                'name': obj.parent.get_full_name(),
                'email': obj.parent.email,
                'phone': obj.parent.phone
            }
        return None

    def get_children(self, obj):
        if obj.role.lower() == 'parent':
            return [
                {
                    'id': child.id,
                    'name': child.get_full_name(),
                    'username': child.username
                } for child in obj.children.all()
            ]
        return []

class GradeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Grade
        fields = ['id', 'name']

class ClassStreamSerializer(serializers.ModelSerializer):
    grade = serializers.CharField(write_only=True)  # Accepts code (e.g., "PP2") or name for create/update

    class Meta:
        model = ClassStream
        fields = ['id', 'grade', 'stream_name']
        read_only_fields = ['id']

    def validate_grade(self, value):
        # Support code (e.g., "PP2") or full name (e.g., "Pre-Primary 2 (PP2)")
        try:
            return Grade.objects.get(code=value)  # Try code first
        except Grade.DoesNotExist:
            try:
                return Grade.objects.get(name=value)  # Fallback to name
            except Grade.DoesNotExist:
                raise serializers.ValidationError("Invalid grade code or name")
            

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['grade'] = GradeSerializer(instance.grade).data
        return ret

class ClassStreamListSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()

    class Meta:
        model = ClassStream
        fields = ['id', 'name']

    def get_name(self, obj):
        return f"{obj.grade.name} - {obj.stream_name}"

class LearningAreaSerializer(serializers.ModelSerializer):
    class Meta:
        model = LearningArea
        fields = ['id', 'name', 'description', 'created_at']

class TeacherAllocationSerializer(serializers.ModelSerializer):
    teacher = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.filter(role__iexact='teacher'))
    class_stream = serializers.PrimaryKeyRelatedField(queryset=ClassStream.objects.all())
    learning_area = serializers.PrimaryKeyRelatedField(queryset=LearningArea.objects.all())

    class Meta:
        model = TeacherAllocation
        fields = ['id', 'teacher', 'class_stream', 'learning_area']

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['teacher'] = {'id': instance.teacher.id, 'name': instance.teacher.get_full_name() or instance.teacher.email}
        ret['class_stream'] = {'id': instance.class_stream.id, 'name': f"{instance.class_stream.grade.name} - {instance.class_stream.stream_name}"}
        ret['learning_area'] = {'id': instance.learning_area.id, 'name': instance.learning_area.name}
        return ret

    def validate(self, data):
        if TeacherAllocation.objects.filter(teacher=data['teacher'], class_stream=data['class_stream'], learning_area=data['learning_area']).exists():
            raise serializers.ValidationError("This allocation already exists.")
        return data

# api/serializers.py (updated ContentSerializer)

class ContentSerializer(serializers.ModelSerializer):
    learning_area = serializers.PrimaryKeyRelatedField(queryset=LearningArea.objects.all())
    media_url = serializers.SerializerMethodField()
    is_youtube = serializers.SerializerMethodField()
    added_date = serializers.SerializerMethodField()

    class Meta:
        model = LearningContent
        fields = ['id', 'title', 'description', 'type', 'url', 'file', 'learning_area', 'created_at', 'media_url', 'is_youtube', 'added_date']
        read_only_fields = ['created_at']

    def get_media_url(self, obj):
        request = self.context.get('request')
        if obj.file and request:
            return request.build_absolute_uri(obj.file.url)
        elif obj.file:
            return obj.file.url
        return obj.url

    def get_is_youtube(self, obj):
        return bool(obj.url and ('youtube.com' in obj.url or 'youtu.be' in obj.url))

    def get_added_date(self, obj):
        if obj.created_at:
            return obj.created_at.isoformat()
        return None

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        if ret['type'] == 'VIDEO' and not ret['is_youtube']:
            ret['url'] = ret['media_url']
        elif ret['type'] == 'DOCUMENT':
            ret['url'] = ret['media_url']
        return ret

    def validate(self, data):
        request = self.context.get('request')
        type_ = data.get('type')
        learning_area = data.get('learning_area')

        # Teacher allocation check
        if request and learning_area:
            if not TeacherAllocation.objects.filter(
                teacher=request.user,
                learning_area=learning_area
            ).exists():
                raise serializers.ValidationError({
                    "learning_area": "You are not allocated to teach this subject."
                })

        url = data.get('url', '').strip()
        file = request.FILES.get('file') if request else None

        if type_ == 'VIDEO':
            has_url = bool(url)
            has_file = bool(file)
            if has_url and has_file:
                raise serializers.ValidationError("Cannot provide both URL and file for video content.")
            if not has_url and not has_file:
                raise serializers.ValidationError("Either YouTube URL or video file is required for video content.")
            if has_url:
                if not ('youtube.com' in url or 'youtu.be' in url):
                    raise serializers.ValidationError({"url": "Please provide a valid YouTube URL."})

        elif type_ == 'DOCUMENT':
            if not file:
                raise serializers.ValidationError({"file": "File is required for document content."})
            if url:
                raise serializers.ValidationError({"url": "URL is not allowed for document content."})
        else:
            raise serializers.ValidationError({"type": "Invalid content type."})

        return data

class ContentProgressSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContentProgress
        fields = ['progress', 'completed', 'last_updated']

class OptionSerializer(serializers.ModelSerializer):
    isCorrect = serializers.BooleanField(source='is_correct', required=False)

    class Meta:
        model = Option
        fields = ['text', 'isCorrect']

class QuestionSerializer(serializers.ModelSerializer):
    options = OptionSerializer(many=True)

    class Meta:
        model = Question
        fields = ['text', 'type', 'options']

class QuizSerializer(serializers.ModelSerializer):
    learning_area = serializers.PrimaryKeyRelatedField(queryset=LearningArea.objects.all(), write_only=True)
    learningArea = LearningAreaSerializer(source='learning_area', read_only=True)
    questions = QuestionSerializer(many=True, read_only=True)  # For GET detail
    _count = serializers.SerializerMethodField()
    attempts = serializers.SerializerMethodField()
    createdAt = serializers.SerializerMethodField()

    class Meta:
        model = Quiz
        fields = [
            'id', 'title', 'description', 'learning_area', 'learningArea',
            'questions', 'createdAt', '_count', 'attempts', 'allow_retakes',
        ]
        read_only_fields = ['id', 'learningArea', 'questions', 'createdAt', '_count', 'attempts']

    def get_createdAt(self, obj):
        return obj.created_at.isoformat()

    def get__count(self, obj):
        return {
            'questions': obj.questions.count(),
            'attempts': obj.attempts.count(),
        }

    def get_attempts(self, obj):
        request = self.context.get('request')
        if request and request.user.role == 'learner':
            attempts = obj.attempts.filter(user=request.user).order_by('-attempted_at')
            return [{'id': a.id, 'score': a.score, 'total': a.total} for a in attempts]
        return []

    def validate(self, data):
        request = self.context.get('request')
        learning_area = data.get('learning_area')
        if request and learning_area:
            if not TeacherAllocation.objects.filter(
                teacher=request.user, learning_area=learning_area
            ).exists():
                raise serializers.ValidationError({
                    "learning_area": "You are not allocated to teach this subject."
                })
        return data

    def create(self, validated_data):
        questions_data = validated_data.pop('questions', [])
        quiz = Quiz.objects.create(
            **validated_data,
            teacher=self.context['request'].user
        )
        for q_data in questions_data:
            options_data = q_data.pop('options', [])
            question = Question.objects.create(quiz=quiz, **q_data)
            for opt_data in options_data:
                opt_data['is_correct'] = opt_data.pop('isCorrect', False)
                Option.objects.create(question=question, **opt_data)
        return quiz

    def update(self, instance, validated_data):
        questions_data = validated_data.pop('questions', None)
        instance.title = validated_data.get('title', instance.title)
        instance.description = validated_data.get('description', instance.description)
        instance.allow_retakes = validated_data.get('allow_retakes', instance.allow_retakes)
        if 'learning_area' in validated_data:
            instance.learning_area = validated_data['learning_area']
        instance.save()
        if questions_data is not None:
            instance.questions.all().delete()
            for q_data in questions_data:
                options_data = q_data.pop('options', [])
                question = Question.objects.create(quiz=instance, **q_data)
                for opt_data in options_data:
                    opt_data['is_correct'] = opt_data.pop('isCorrect', False)
                    Option.objects.create(question=question, **opt_data)
        return instance

class QuizListSerializer(QuizSerializer):
    class Meta(QuizSerializer.Meta):
        fields = ['id', 'title', 'description', 'learningArea', 'createdAt', '_count', 'allow_retakes']

class QuizAttemptSerializer(serializers.ModelSerializer):
    quiz = QuizSerializer()
    attemptedAt = serializers.DateTimeField(source='attempted_at')

    class Meta:
        model = QuizAttempt
        fields = ['id', 'score', 'total', 'attemptedAt', 'quiz']

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ['id', 'date', 'status', 'remarks']

# api/serializers.py (update StudentSerializer – simple addition, no new serializer needed)

class StudentSerializer(serializers.ModelSerializer):
    firstName = serializers.CharField(source='first_name')
    lastName = serializers.CharField(source='last_name')
    gradeLevel = serializers.SerializerMethodField()
    class_stream = serializers.SerializerMethodField()  # ← ADD THIS: simple class display
    quizAttempts = QuizAttemptSerializer(source='quiz_attempts', many=True)
    attendance = AttendanceSerializer(source='attendance_records', many=True)

    class Meta:
        model = CustomUser
        fields = ['id', 'firstName', 'lastName', 'gradeLevel', 'class_stream', 'quizAttempts', 'attendance']  # ← ADD 'class_stream'

    def get_gradeLevel(self, obj):
        if obj.grade_level:
            try:
                grade = Grade.objects.get(code=obj.grade_level)
                return {'id': grade.code, 'name': grade.name}
            except Grade.DoesNotExist:
                return {'id': obj.grade_level, 'name': obj.grade_level}
        return None

    # ← ADD THIS METHOD: simple and matches your admin table format (e.g., "Grade 1 - Red")
    def get_class_stream(self, obj):
        if obj.class_stream:
            parts = []
            if obj.class_stream.grade and obj.class_stream.grade.name:
                parts.append(obj.class_stream.grade.name.strip())
            if obj.class_stream.stream_name:
                parts.append(obj.class_stream.stream_name.strip())
            if parts:
                return {
                    "id": obj.class_stream.id,
                    "name": " - ".join(parts)  # ← "Grade 1 - Red" format (or " ".join(parts) if no dash needed – change to " ".join(parts) if preferred)
                }
        return None  # Frontend will show "No class assigned"
    
class StudentListSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()
    admissionNumber = serializers.CharField(source='username')

    class Meta:
        model = CustomUser
        fields = ['id', 'name', 'admissionNumber']

    def get_name(self, obj):
        full = f"{obj.first_name} {obj.last_name}".strip()
        return full if full else obj.email