"""
Сериализаторы для домашних заданий.
"""
from rest_framework import serializers
from django.utils import timezone
from .models import Homework, HomeworkSubmission, HomeworkFile, HomeworkAssignmentFile, HomeworkAIAgent
from apps.users.serializers import UserSerializer
from apps.users.mixins import TimezoneAwareSerializerMixin


class HomeworkAIAgentSerializer(serializers.ModelSerializer):
    """Сериализатор ИИ-агента (без api_key)."""
    class Meta:
        model = HomeworkAIAgent
        fields = ['id', 'name', 'openai_url', 'model_name', 'is_default', 'order', 'is_active']
        read_only_fields = ['id', 'name', 'openai_url', 'model_name', 'is_default', 'order', 'is_active']


IMAGE_EXTENSIONS = frozenset(['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg', 'ico'])


def _is_image_filename(filename):
    """Определение по расширению, что файл — изображение (для превью и модального просмотра)."""
    if not filename or '.' not in str(filename).strip():
        return False
    ext = str(filename).rsplit('.', 1)[-1].lower()
    return ext in IMAGE_EXTENSIONS


class HomeworkFileSerializer(serializers.ModelSerializer):
    """Сериализатор файла ДЗ (решения/отзывы)."""
    
    uploaded_by = UserSerializer(read_only=True)
    is_image = serializers.SerializerMethodField()

    def get_is_image(self, obj):
        if _is_image_filename(obj.filename):
            return True
        if getattr(obj, 'file', None) and obj.file.name:
            return _is_image_filename(obj.file.name)
        return False

    class Meta:
        model = HomeworkFile
        fields = [
            'id',
            'file_type',
            'file',
            'filename',
            'file_size',
            'uploaded_by',
            'created_at',
            'is_image',
        ]
        read_only_fields = ['uploaded_by', 'created_at']


class HomeworkAssignmentFileSerializer(serializers.ModelSerializer):
    """Сериализатор файла задания (прямая связь Homework → файл)."""
    
    uploaded_by = UserSerializer(read_only=True)
    file_type = serializers.ReadOnlyField(default='assignment')
    is_image = serializers.SerializerMethodField()

    def get_is_image(self, obj):
        if _is_image_filename(obj.filename):
            return True
        if getattr(obj, 'file', None) and obj.file.name:
            return _is_image_filename(obj.file.name)
        return False

    class Meta:
        model = HomeworkAssignmentFile
        fields = [
            'id',
            'file_type',
            'file',
            'filename',
            'file_size',
            'uploaded_by',
            'created_at',
            'is_image',
        ]
        read_only_fields = ['uploaded_by', 'created_at']


class HomeworkSerializer(TimezoneAwareSerializerMixin, serializers.ModelSerializer):
    """Сериализатор домашнего задания."""
    
    mentor = UserSerializer(read_only=True)
    assigned_to = UserSerializer(many=True, read_only=True)
    files = serializers.SerializerMethodField()
    is_overdue = serializers.BooleanField(read_only=True)

    def get_files(self, obj):
        """Файлы задания — из модели HomeworkAssignmentFile (прямая связь)."""
        if not hasattr(obj, 'assignment_files'):
            return []
        return HomeworkAssignmentFileSerializer(obj.assignment_files.all(), many=True).data
    
    class Meta:
        model = Homework
        fields = [
            'id',
            'title',
            'description',
            'mentor',
            'lesson',
            'assigned_to',
            'attachment',
            'attachment_url',
            'deadline',
            'max_score',
            'passing_score',
            'allow_late_submission',
            'auto_check_enabled',
            'ai_check_enabled',
            'requires_file',
            'allowed_file_types',
            'max_file_size',
            'status',
            'fill_later',
            'total_submissions',
            'checked_submissions',
            'returned_submissions',
            'average_score',
            'is_overdue',
            'files',
            'created_at',
            'updated_at',
            'published_at'
        ]
        read_only_fields = [
            'mentor',
            'total_submissions',
            'checked_submissions',
            'returned_submissions',
            'average_score',
            'created_at',
            'updated_at',
            'published_at'
        ]
        timezone_aware_fields = ['deadline', 'created_at', 'updated_at', 'published_at']


class HomeworkListSerializer(serializers.ModelSerializer):
    """Сериализатор списка ДЗ (упрощенный)."""
    
    mentor = UserSerializer(read_only=True)
    is_overdue = serializers.BooleanField(read_only=True)
    students = serializers.SerializerMethodField()
    student_score = serializers.SerializerMethodField()
    lesson_subject = serializers.SerializerMethodField()
    ai_draft_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Homework
        fields = [
            'id',
            'title',
            'mentor',
            'lesson',
            'lesson_subject',
            'deadline',
            'max_score',
            'passing_score',
            'status',
            'fill_later',
            'total_submissions',
            'checked_submissions',
            'returned_submissions',
            'average_score',
            'is_overdue',
            'created_at',
            'published_at',
            'students',
            'student_score',
            'ai_draft_count',
        ]
    
    def get_lesson_subject(self, obj):
        """Получить название предмета из урока."""
        if obj.lesson and obj.lesson.subject:
            return obj.lesson.subject.name
        if obj.lesson and obj.lesson.mentor_subject:
            return obj.lesson.mentor_subject.name
        if obj.lesson and obj.lesson.subject_name:
            return obj.lesson.subject_name
        return None
    
    def get_students(self, obj):
        """Получить список студентов для ментора."""
        request = self.context.get('request')
        if not request or request.user.role != 'mentor':
            return None
        
        # Получаем всех назначенных студентов
        assigned_students = list(obj.assigned_to.all())
        
        # Оптимизация: получаем все submissions одним запросом и группируем в Python
        # Используем prefetch_related из views, но все равно нужно получить последнюю для каждого студента
        all_submissions = list(obj.submissions.all().order_by('-submitted_at'))
        
        # Группируем submissions по student_id, берем первую (последнюю по submitted_at)
        submissions_by_student = {}
        for submission in all_submissions:
            student_id = submission.student_id
            if student_id not in submissions_by_student:
                submissions_by_student[student_id] = submission
        
        students = []
        for student in assigned_students:
            submission = submissions_by_student.get(student.id)
            if submission:
                students.append({
                    'id': student.id,
                    'first_name': student.first_name,
                    'last_name': student.last_name,
                    'score': submission.score,
                    'status': submission.status,
                })
            else:
                # Если решения нет, все равно показываем студента
                students.append({
                    'id': student.id,
                    'first_name': student.first_name,
                    'last_name': student.last_name,
                    'score': None,
                    'status': None,
                })
        
        return students if students else None
    
    def get_student_score(self, obj):
        """Получить оценку студента."""
        request = self.context.get('request')
        if not request or request.user.role != 'client':
            return None
        
        # Получаем последнюю попытку студента (может быть несколько попыток)
        submission = obj.submissions.filter(student=request.user).order_by('-submitted_at').first()
        if submission:
            return {
                'score': submission.score,
                'max_score': obj.max_score,
                'status': submission.status,
            }
        return None
    
    def get_ai_draft_count(self, obj):
        """Количество решений с черновиком от ИИ. Только для ментора. Берём из поля модели ai_draft_submissions."""
        request = self.context.get('request')
        if not request or request.user.role != 'mentor':
            return 0
        return getattr(obj, 'ai_draft_submissions', 0)


class HomeworkCreateSerializer(serializers.ModelSerializer):
    """Сериализатор создания ДЗ."""
    
    lesson_id = serializers.IntegerField(required=False, allow_null=True)
    assigned_to_ids = serializers.ListField(
        child=serializers.IntegerField(),
        required=False,
        allow_empty=True
    )
    
    class Meta:
        model = Homework
        extra_kwargs = {
            'description': {'required': False, 'allow_blank': True},
        }
        fields = [
            'title',
            'description',
            'lesson_id',
            'assigned_to_ids',
            'attachment',
            'attachment_url',
            'deadline',
            'max_score',
            'passing_score',
            'allow_late_submission',
            'auto_check_enabled',
            'ai_check_enabled',
            'requires_file',
            'allowed_file_types',
            'max_file_size',
            'status',
            'fill_later'
        ]
    
    def validate_lesson_id(self, value):
        """Проверка занятия."""
        if value:
            from apps.schedule.models import Lesson
            try:
                lesson = Lesson.objects.get(id=value)
                # Проверяем что пользователь - ментор занятия
                user = self.context['request'].user
                if lesson.mentor != user:
                    raise serializers.ValidationError(
                        'Вы не являетесь ментором этого занятия'
                    )
            except Lesson.DoesNotExist:
                raise serializers.ValidationError('Занятие не найдено')
        return value
    
    def create(self, validated_data):
        """Создание ДЗ."""
        from apps.schedule.models import Lesson
        from apps.users.models import User
        
        lesson_id = validated_data.pop('lesson_id', None)
        assigned_to_ids = validated_data.pop('assigned_to_ids', [])
        user = self.context['request'].user
        
        homework = Homework.objects.create(
            mentor=user,
            lesson_id=lesson_id,
            **validated_data
        )
        
        # Добавляем студентов
        if assigned_to_ids:
            students = User.objects.filter(id__in=assigned_to_ids)
            homework.assigned_to.set(students)
        
        # Если задание для занятия, автоматически назначаем клиента
        if lesson_id:
            lesson = Lesson.objects.get(id=lesson_id)
            if lesson.client and lesson.client.user:
                homework.assigned_to.add(lesson.client.user)
        
        return homework
    
    def update(self, instance, validated_data):
        """Обновление ДЗ."""
        from apps.schedule.models import Lesson
        from apps.users.models import User
        
        lesson_id = validated_data.pop('lesson_id', None)
        assigned_to_ids = validated_data.pop('assigned_to_ids', None)
        
        # Обновляем основные поля
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        
        # Обновляем связь с уроком
        if lesson_id is not None:
            instance.lesson_id = lesson_id
            instance.save()
        
        # Обновляем назначенных студентов
        if assigned_to_ids is not None:
            students = User.objects.filter(id__in=assigned_to_ids)
            instance.assigned_to.set(students)
            
            # Если задание для занятия, автоматически добавляем клиента
            if lesson_id:
                lesson = Lesson.objects.get(id=lesson_id)
                if lesson.client and lesson.client.user:
                    instance.assigned_to.add(lesson.client.user)
        
        return instance


class HomeworkSubmissionSerializer(TimezoneAwareSerializerMixin, serializers.ModelSerializer):
    """Сериализатор решения ДЗ."""
    
    student = UserSerializer(read_only=True)
    checked_by = UserSerializer(read_only=True)
    homework = HomeworkListSerializer(read_only=True)
    files = HomeworkFileSerializer(many=True, read_only=True)
    ai_feedback_html = serializers.SerializerMethodField()
    feedback_html = serializers.SerializerMethodField()

    class Meta:
        model = HomeworkSubmission
        fields = [
            'id',
            'homework',
            'student',
            'content',
            'attachment',
            'attachment_url',
            'status',
            'score',
            'passed',
            'feedback',
            'feedback_html',
            'checked_by',
            'checked_at',
            'ai_score',
            'ai_feedback',
            'ai_feedback_html',
            'ai_checked_at',
            'graded_by_ai',
            'attempt_number',
            'is_late',
            'files',
            'submitted_at',
            'updated_at'
        ]
        read_only_fields = [
            'student',
            'checked_by',
            'checked_at',
            'ai_score',
            'ai_feedback',
            'ai_checked_at',
            'graded_by_ai',
            'attempt_number',
            'is_late',
            'submitted_at',
            'updated_at'
        ]
        timezone_aware_fields = ['checked_at', 'ai_checked_at', 'submitted_at', 'updated_at']

    def get_ai_feedback_html(self, obj):
        """HTML для отображения ai_feedback: markdown + LaTeX ($a$, $$...$$) → HTML/MathML."""
        from .utils import feedback_to_html
        return feedback_to_html(obj.ai_feedback) if obj.ai_feedback else ''

    def get_feedback_html(self, obj):
        """HTML для отображения комментария проверки: markdown + LaTeX → HTML/MathML."""
        from .utils import feedback_to_html
        return feedback_to_html(obj.feedback) if obj.feedback else ''


class HomeworkSubmissionCreateSerializer(serializers.ModelSerializer):
    """Сериализатор создания решения ДЗ."""
    
    homework_id = serializers.IntegerField(write_only=True)
    
    class Meta:
        model = HomeworkSubmission
        fields = [
            'homework_id',
            'content',
            'attachment',
            'attachment_url'
        ]
    
    def validate_homework_id(self, value):
        """Проверка ДЗ."""
        try:
            homework = Homework.objects.get(id=value)
        except Homework.DoesNotExist:
            raise serializers.ValidationError('Домашнее задание не найдено')
        
        # Проверяем что задание опубликовано
        if homework.status != 'published':
            raise serializers.ValidationError('Задание еще не опубликовано')
        
        # Проверяем дедлайн если не разрешена поздняя сдача
        if not homework.allow_late_submission and homework.is_overdue():
            raise serializers.ValidationError('Дедлайн прошел')
        
        # Проверяем что пользователь назначен на это задание
        user = self.context['request'].user
        if not homework.assigned_to.filter(id=user.id).exists():
            raise serializers.ValidationError('Вам не назначено это задание')
        
        return value
    
    def validate(self, attrs):
        """Общая валидация."""
        homework = Homework.objects.get(id=attrs['homework_id'])
        
        # Проверяем, что есть либо текст, либо файл/ссылка
        has_content = bool(attrs.get('content', '').strip())
        has_attachment = bool(attrs.get('attachment')) or bool(attrs.get('attachment_url', '').strip())
        
        if not has_content and not has_attachment:
            raise serializers.ValidationError({
                'content': 'Необходимо указать текст ответа или прикрепить файл'
            })
        
        # Если требуется файл, проверяем его наличие
        # Но если есть текстовый ответ, файл не обязателен
        if homework.requires_file and not has_attachment and not has_content:
            raise serializers.ValidationError({
                'attachment': 'Требуется прикрепить файл или указать текстовый ответ'
            })
        
        return attrs
    
    def create(self, validated_data):
        """Создание или обновление решения."""
        homework_id = validated_data.pop('homework_id')
        homework = Homework.objects.get(id=homework_id)
        user = self.context['request'].user
        
        # Проверяем, есть ли submission со статусом 'returned' для этого студента и задания
        returned_submission = HomeworkSubmission.objects.filter(
            homework=homework,
            student=user,
            status='returned'
        ).order_by('-submitted_at').first()
        
        if returned_submission:
            # Обновляем существующее submission, которое было возвращено на доработку
            # Перезаписываем содержимое, но сохраняем тот же ID и attempt_number
            if 'content' in validated_data:
                returned_submission.content = validated_data['content']
            if 'attachment' in validated_data and validated_data['attachment']:
                returned_submission.attachment = validated_data['attachment']
            if 'attachment_url' in validated_data:
                returned_submission.attachment_url = validated_data['attachment_url']
            returned_submission.status = 'pending'  # Меняем статус на pending
            returned_submission.feedback = ''  # Очищаем feedback
            returned_submission.checked_by = None  # Очищаем checked_by
            returned_submission.checked_at = None  # Очищаем checked_at
            returned_submission.score = None  # Очищаем оценку
            returned_submission.passed = False  # Сбрасываем passed
            returned_submission.ai_score = None  # Очищаем AI оценку
            returned_submission.ai_feedback = ''  # Очищаем AI feedback
            returned_submission.ai_checked_at = None  # Очищаем AI checked_at
            returned_submission.save()
            
            submission = returned_submission
        else:
            # Создаем новое submission
            # Определяем номер попытки
            last_submission = HomeworkSubmission.objects.filter(
                homework=homework,
                student=user
            ).order_by('-attempt_number').first()
            
            attempt_number = 1
            if last_submission:
                attempt_number = last_submission.attempt_number + 1
            
            submission = HomeworkSubmission.objects.create(
                homework=homework,
                student=user,
                attempt_number=attempt_number,
                **validated_data
            )
        
        # Проверяем опоздание
        submission.check_if_late()
        
        # Обновляем статистику задания
        homework.update_statistics()
        
        return submission


# Шкала оценки ментором: от 1 до 5; зачёт при 3 и выше
MENTOR_GRADE_MIN = 1
MENTOR_GRADE_MAX = 5
MENTOR_PASS_THRESHOLD = 3


class HomeworkGradeSerializer(serializers.Serializer):
    """Сериализатор выставления оценки (ментор оценивает от 1 до 5)."""
    
    score = serializers.IntegerField(
        min_value=MENTOR_GRADE_MIN,
        max_value=MENTOR_GRADE_MAX,
        required=True
    )
    
    feedback = serializers.CharField(
        required=False,
        allow_blank=True
    )
    
    def validate_score(self, value):
        """Проверка балла: только 1–5."""
        if value < MENTOR_GRADE_MIN or value > MENTOR_GRADE_MAX:
            raise serializers.ValidationError(
                f'Оценка должна быть от {MENTOR_GRADE_MIN} до {MENTOR_GRADE_MAX}'
            )
        return value
    
    def save(self):
        """Выставить оценку."""
        submission = self.instance
        user = self.context['request'].user
        score = self.validated_data['score']
        
        submission.grade(
            score=score,
            feedback=self.validated_data.get('feedback', ''),
            checked_by=user
        )
        # Зачёт при 3 и выше по шкале 1–5
        submission.passed = score >= MENTOR_PASS_THRESHOLD
        submission.save(update_fields=['passed'])
        
        return submission


class HomeworkReturnSerializer(serializers.Serializer):
    """Сериализатор возврата на доработку."""
    
    feedback = serializers.CharField(required=True)
    
    def save(self):
        """Вернуть на доработку."""
        submission = self.instance
        user = self.context['request'].user
        
        submission.return_for_revision(
            feedback=self.validated_data['feedback'],
            checked_by=user
        )
        
        return submission
