"""
Сериализаторы для чата и сообщений.
"""
from rest_framework import serializers
from django.db import models
from .models import Chat, ChatParticipant, Message, MessageFile, MessageRead, MessageReaction
from .services import ChatService
from apps.users.serializers import UserSerializer
from apps.users.mixins import TimezoneAwareSerializerMixin
from apps.users.utils import format_datetime_for_user


class ChatParticipantSerializer(serializers.ModelSerializer):
    """Сериализатор участника чата."""
    
    user = UserSerializer(read_only=True)
    
    class Meta:
        model = ChatParticipant
        fields = [
            'id',
            'user',
            'role',
            'unread_count',
            'last_read_at',
            'is_muted',
            'is_pinned',
            'joined_at'
        ]
        read_only_fields = ['unread_count', 'last_read_at', 'joined_at']


class MessageFileSerializer(serializers.ModelSerializer):
    """Сериализатор файла сообщения."""
    
    file = serializers.SerializerMethodField()
    
    class Meta:
        model = MessageFile
        fields = [
            'id',
            'file',
            'file_name',
            'file_size',
            'file_type',
            'created_at'
        ]
        read_only_fields = ['file_name', 'file_size', 'file_type', 'created_at']
    
    def get_file(self, obj):
        """Получить полный URL файла."""
        request = self.context.get('request')
        if request and obj.file:
            return request.build_absolute_uri(obj.file.url)
        elif obj.file:
            # Если нет request, возвращаем относительный URL
            return obj.file.url
        return None


class MessageReactionSerializer(serializers.ModelSerializer):
    """Сериализатор реакции на сообщение."""
    
    user = UserSerializer(read_only=True)
    
    class Meta:
        model = MessageReaction
        fields = ['id', 'user', 'emoji', 'created_at']
        read_only_fields = ['user', 'created_at']


class MessageSerializer(TimezoneAwareSerializerMixin, serializers.ModelSerializer):
    """Сериализатор сообщения."""
    
    sender = UserSerializer(read_only=True)
    files = MessageFileSerializer(many=True, read_only=True)
    reactions = MessageReactionSerializer(many=True, read_only=True)
    reply_to = serializers.SerializerMethodField()
    is_read = serializers.SerializerMethodField()
    is_read_by_others = serializers.SerializerMethodField()
    
    class Meta:
        model = Message
        fields = [
            'id',
            'uuid',
            'chat',
            'sender',
            'message_type',
            'content',
            'reply_to',
            'files',
            'reactions',
            'is_edited',
            'edited_at',
            'is_deleted',
            'is_read',
            'is_read_by_others',
            'created_at'
        ]
        read_only_fields = [
            'uuid',
            'sender',
            'is_edited',
            'edited_at',
            'is_deleted',
            'created_at'
        ]
        timezone_aware_fields = ['created_at', 'edited_at']
    
    def get_reply_to(self, obj):
        """Получить сообщение, на которое отвечают."""
        if obj.reply_to:
            return {
                'uuid': str(obj.reply_to.uuid),
                'sender': obj.reply_to.sender.get_full_name() if obj.reply_to.sender else 'System',
                'content': obj.reply_to.content[:100]
            }
        return None
    
    def get_is_read(self, obj):
        """Проверка прочитано ли сообщение текущим пользователем."""
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            # Оптимизация: используем предзагруженные reads если доступны
            if hasattr(obj, '_prefetched_objects_cache') and 'reads' in obj._prefetched_objects_cache:
                reads = obj._prefetched_objects_cache['reads']
                return any(read.user_id == request.user.id for read in reads)
            
            # Fallback на запрос, если prefetch не был выполнен
            return MessageRead.objects.filter(
                message=obj,
                user=request.user
            ).exists()
        return False
    
    def get_is_read_by_others(self, obj):
        """Проверка прочитано ли сообщение другими участниками чата (для отображения статуса прочитанности)."""
        request = self.context.get('request')
        if not request or not request.user.is_authenticated:
            return False
        
        # Проверяем только для сообщений, отправленных текущим пользователем
        if obj.sender_id != request.user.id:
            return False
        
        # Получаем всех участников чата кроме отправителя
        chat = obj.chat
        other_participants = chat.participants.exclude(user_id=obj.sender_id)
        
        if not other_participants.exists():
            return False
        
        # Проверяем, прочитано ли сообщение хотя бы одним другим участником
        # Оптимизация: используем предзагруженные reads если доступны
        if hasattr(obj, '_prefetched_objects_cache') and 'reads' in obj._prefetched_objects_cache:
            reads = obj._prefetched_objects_cache['reads']
            other_participant_ids = set(other_participants.values_list('user_id', flat=True))
            return any(read.user_id in other_participant_ids for read in reads)
        
        # Fallback на запрос
        other_participant_ids = list(other_participants.values_list('user_id', flat=True))
        return MessageRead.objects.filter(
            message=obj,
            user_id__in=other_participant_ids
        ).exists()


class MessageCreateSerializer(serializers.ModelSerializer):
    """Сериализатор создания сообщения."""
    
    reply_to_uuid = serializers.UUIDField(required=False, allow_null=True)
    content = serializers.CharField(required=False, allow_blank=True)
    files = serializers.ListField(
        child=serializers.FileField(),
        required=False,
        allow_empty=True
    )
    preloaded_files = serializers.CharField(
        required=False,
        allow_blank=True,
        help_text="JSON строка со списком предзагруженных файлов: [{'filename': 'uuid.ext', 'original_name': 'name.ext', 'size': 1234, 'content_type': 'image/jpeg'}]"
    )
    
    class Meta:
        model = Message
        fields = ['chat', 'content', 'message_type', 'reply_to_uuid', 'files', 'preloaded_files']
    
    def validate(self, attrs):
        """Валидация."""
        # Проверяем доступ к чату
        request = self.context['request']
        chat = attrs['chat']
        
        if not ChatParticipant.objects.filter(chat=chat, user=request.user).exists():
            raise serializers.ValidationError({
                'chat': 'У вас нет доступа к этому чату'
            })
        
        # Проверяем, что есть либо content, либо файлы
        content = attrs.get('content', '').strip()
        files = attrs.get('files', [])
        preloaded_files = attrs.get('preloaded_files', [])
        
        # Парсим preloaded_files если это строка
        if isinstance(preloaded_files, str):
            import json
            try:
                preloaded_files = json.loads(preloaded_files)
            except json.JSONDecodeError:
                preloaded_files = []
        
        has_content = bool(content)
        has_files = bool(files) or bool(preloaded_files)
        
        if not has_content and not has_files:
            raise serializers.ValidationError({
                'content': 'Сообщение не может быть пустым. Укажите текст или прикрепите файлы.'
            })
        
        # Проверяем reply_to
        reply_to_uuid = attrs.pop('reply_to_uuid', None)
        if reply_to_uuid:
            try:
                attrs['reply_to'] = Message.objects.get(uuid=reply_to_uuid, chat=chat)
            except Message.DoesNotExist:
                raise serializers.ValidationError({
                    'reply_to_uuid': 'Сообщение не найдено'
                })
        
        # Устанавливаем пустую строку для content если его нет
        if not content:
            attrs['content'] = ''
        
        return attrs
    
    def create(self, validated_data):
        """Создание сообщения."""
        files_data = validated_data.pop('files', [])
        preloaded_files_data = validated_data.pop('preloaded_files', '')
        user = self.context['request'].user
        chat = validated_data['chat']
        
        message = Message.objects.create(
            sender=user,
            **validated_data
        )
        
        # Обрабатываем предзагруженные файлы
        from .utils import move_file_from_preload_to_chat
        from django.core.files import File
        from django.conf import settings
        import os
        import json
        
        # Парсим JSON строку
        preloaded_files_list = []
        if preloaded_files_data:
            if isinstance(preloaded_files_data, str):
                try:
                    parsed = json.loads(preloaded_files_data)
                    if isinstance(parsed, list):
                        preloaded_files_list = [item for item in parsed if isinstance(item, dict)]
                except json.JSONDecodeError:
                    preloaded_files_list = []
            elif isinstance(preloaded_files_data, list):
                preloaded_files_list = [item for item in preloaded_files_data if isinstance(item, dict)]
        
        for preloaded_file in preloaded_files_list:
                try:
                    filename = preloaded_file.get('filename')
                    original_name = preloaded_file.get('original_name', filename)
                    file_size = preloaded_file.get('size', 0)
                    content_type = preloaded_file.get('content_type', 'application/octet-stream')
                    
                    # Перемещаем файл из preload в основную директорию
                    new_file_path = move_file_from_preload_to_chat(chat.id, filename)
                    
                    # Создаем запись MessageFile
                    full_path = os.path.join(settings.MEDIA_ROOT, new_file_path)
                    with open(full_path, 'rb') as f:
                        django_file = File(f, name=os.path.basename(new_file_path))
                        MessageFile.objects.create(
                            message=message,
                            file=django_file,
                            file_name=original_name,
                            file_size=file_size,
                            file_type=content_type
                        )
                except Exception as e:
                    # Логируем ошибку, но не прерываем создание сообщения
                    import logging
                    logger = logging.getLogger(__name__)
                    logger.error(f"Ошибка при обработке предзагруженного файла {preloaded_file}: {e}")
        
        # Обрабатываем файлы, загруженные напрямую (для обратной совместимости)
        for file in files_data:
            MessageFile.objects.create(
                message=message,
                file=file,
                file_name=file.name,
                file_size=file.size,
                file_type=file.content_type
            )
        
        return message


class ChatSerializer(TimezoneAwareSerializerMixin, serializers.ModelSerializer):
    """Сериализатор чата (список)."""
    
    created_by = UserSerializer(read_only=True)
    last_message = serializers.SerializerMethodField()
    my_participant = serializers.SerializerMethodField()
    participants_count = serializers.SerializerMethodField()
    other_participant = serializers.SerializerMethodField()
    
    class Meta:
        model = Chat
        fields = [
            'id',
            'uuid',
            'chat_type',
            'name',
            'description',
            'avatar',
            'created_by',
            'lesson',
            'participants_count',
            'last_message',
            'my_participant',
            'other_participant',
            'messages_count',
            'last_message_at',
            'is_archived',
            'created_at'
        ]
        read_only_fields = [
            'uuid',
            'created_by',
            'messages_count',
            'last_message_at',
            'created_at'
        ]
        timezone_aware_fields = ['created_at', 'last_message_at']
    
    def get_participants_count(self, obj):
        """Количество участников."""
        # Оптимизация: используем предзагруженные participants если доступны
        if hasattr(obj, '_prefetched_objects_cache') and 'participants' in obj._prefetched_objects_cache:
            return len(obj._prefetched_objects_cache['participants'])
        return obj.participants.count()
    
    def get_last_message(self, obj):
        """Получить последнее сообщение."""
        # Оптимизация: используем предзагруженные messages если доступны
        if hasattr(obj, '_prefetched_objects_cache') and 'messages' in obj._prefetched_objects_cache:
            messages = [m for m in obj._prefetched_objects_cache['messages'] if not m.is_deleted]
            last_message = messages[0] if messages else None
        else:
            last_message = obj.messages.filter(is_deleted=False).select_related('sender').prefetch_related('files', 'reads').first()
        
        if last_message:
            # Получаем информацию о файлах
            files_data = []
            if hasattr(last_message, '_prefetched_objects_cache') and 'files' in last_message._prefetched_objects_cache:
                files = last_message._prefetched_objects_cache['files']
            else:
                files = last_message.files.all()
            
            for file in files:
                files_data.append({
                    'id': file.id,
                    'file_name': file.file_name,
                    'file_type': file.file_type,
                    'file_size': file.file_size
                })
            
            # Проверяем, прочитано ли сообщение другими участниками (для отображения статуса)
            is_read_by_others = False
            request = self.context.get('request')
            if request and request.user.is_authenticated and last_message.sender_id == request.user.id:
                # Получаем всех участников чата кроме отправителя
                other_participants = obj.participants.exclude(user_id=last_message.sender_id)
                if other_participants.exists():
                    # Проверяем, прочитано ли сообщение хотя бы одним другим участником
                    if hasattr(last_message, '_prefetched_objects_cache') and 'reads' in last_message._prefetched_objects_cache:
                        reads = last_message._prefetched_objects_cache['reads']
                        other_participant_ids = set(other_participants.values_list('user_id', flat=True))
                        is_read_by_others = any(read.user_id in other_participant_ids for read in reads)
                    else:
                        other_participant_ids = list(other_participants.values_list('user_id', flat=True))
                        is_read_by_others = MessageRead.objects.filter(
                            message=last_message,
                            user_id__in=other_participant_ids
                        ).exists()
            
            return {
                'uuid': str(last_message.uuid),
                'sender': last_message.sender.get_full_name() if last_message.sender else 'System',
                'sender_id': last_message.sender_id,
                'content': last_message.content[:100] if last_message.content else '',
                'message_type': last_message.message_type,
                'files': files_data,
                'is_read_by_others': is_read_by_others,
                'created_at': format_datetime_for_user(last_message.created_at, request.user.timezone) if last_message.created_at and request and request.user.is_authenticated else (last_message.created_at.isoformat() if last_message.created_at else None)
            }
        return None
    
    def get_my_participant(self, obj):
        """Получить данные участника для текущего пользователя."""
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            # Оптимизация: используем предзагруженные participants если доступны
            if hasattr(obj, '_prefetched_objects_cache') and 'participants' in obj._prefetched_objects_cache:
                participants = obj._prefetched_objects_cache['participants']
                participant = next((p for p in participants if p.user_id == request.user.id), None)
            else:
                try:
                    participant = obj.participants.get(user=request.user)
                except ChatParticipant.DoesNotExist:
                    participant = None
            
            if participant:
                return {
                    'unread_count': participant.unread_count,
                    'is_muted': participant.is_muted,
                    'is_pinned': participant.is_pinned
                }
        return None
    
    def get_other_participant(self, obj):
        """Получить информацию о собеседнике для личных чатов."""
        if obj.chat_type != 'direct':
            return None
        
        request = self.context.get('request')
        if not request or not request.user.is_authenticated:
            return None
        
        # Оптимизация: используем предзагруженные participants если доступны
        if hasattr(obj, '_prefetched_objects_cache') and 'participants' in obj._prefetched_objects_cache:
            participants = obj._prefetched_objects_cache['participants']
            other_participant = next((p for p in participants if p.user_id != request.user.id), None)
        else:
            other_participant = obj.participants.exclude(user=request.user).select_related('user').first()
        
        if other_participant and other_participant.user:
            from datetime import timedelta
            from django.utils import timezone
            
            user = other_participant.user
            # КРИТИЧНО: Обновляем объект пользователя из базы данных, чтобы получить актуальное значение last_activity
            # Это необходимо, так как middleware мог обновить last_activity после загрузки объекта
            try:
                user.refresh_from_db(fields=['last_activity'])
            except Exception:
                # Если не удалось обновить, используем текущее значение
                pass
            
            # Определяем статус онлайн (активен в последние 15 минут)
            # Интервал 15 минут для определения онлайн статуса
            is_online = False
            if user.last_activity:
                time_diff = timezone.now() - user.last_activity
                # Пользователь считается онлайн если активен в последние 15 минут
                is_online = time_diff.total_seconds() < 900  # 15 минут = 900 секунд
            # Если last_activity отсутствует, пользователь точно не онлайн
            
            # Получаем полный URL аватара
            avatar_url = None
            if user.avatar:
                request = self.context.get('request')
                if request:
                    avatar_url = request.build_absolute_uri(user.avatar.url)
                else:
                    avatar_url = user.avatar.url
            
            return {
                'id': user.id,
                'email': user.email,
                'first_name': user.first_name,
                'last_name': user.last_name,
                'full_name': user.get_full_name() or user.email,
                'avatar': avatar_url,
                'role': user.role,
                'is_online': is_online,
                'last_activity': format_datetime_for_user(user.last_activity, request.user.timezone) if user.last_activity and request and request.user.is_authenticated else (user.last_activity.isoformat() if user.last_activity else None)
                }
        return None


class ChatCreateSerializer(serializers.ModelSerializer):
    """Сериализатор создания чата."""
    
    participant_ids = serializers.ListField(
        child=serializers.IntegerField(),
        required=True,
        allow_empty=False
    )
    
    class Meta:
        model = Chat
        fields = ['chat_type', 'name', 'description', 'avatar', 'participant_ids']
    
    def validate_participant_ids(self, value):
        """Валидация участников."""
        from apps.users.models import User
        
        # Проверяем что все пользователи существуют
        users = User.objects.filter(id__in=value)
        if users.count() != len(value):
            raise serializers.ValidationError('Некоторые пользователи не найдены')
        
        return value
    
    def validate(self, attrs):
        """Валидация."""
        # Для личного чата нужно ровно 2 участника (текущий + 1)
        if attrs['chat_type'] == 'direct':
            if len(attrs['participant_ids']) != 1:
                raise serializers.ValidationError({
                    'participant_ids': 'Для личного чата нужен ровно 1 участник'
                })
        
        return attrs
    
    def create(self, validated_data):
        """Создание чата."""
        from apps.users.models import User
        
        participant_ids = validated_data.pop('participant_ids')
        user = self.context['request'].user
        
        # Для личного чата используем сервис с защитой от race condition
        if validated_data['chat_type'] == 'direct':
            other_user = User.objects.get(id=participant_ids[0])
            chat, _ = ChatService.get_or_create_direct_chat(
                user1=user,
                user2=other_user,
                created_by=user
            )
            return chat
        
        # Для группового чата - обычная логика
        chat = Chat.objects.create(
            created_by=user,
            **validated_data
        )
        
        # Добавляем создателя как участника
        ChatParticipant.objects.create(
            chat=chat,
            user=user,
            role='admin'
        )
        
        # Добавляем остальных участников
        users = list(User.objects.filter(id__in=participant_ids))
        participants_to_create = [
            ChatParticipant(
                chat=chat,
                user=participant_user,
                role='member'
            )
            for participant_user in users
        ]
        if participants_to_create:
            ChatParticipant.objects.bulk_create(participants_to_create)
        
        return chat


class ChatDetailSerializer(ChatSerializer):
    """Детальный сериализатор чата (с участниками)."""
    
    participants = ChatParticipantSerializer(many=True, read_only=True)
    
    class Meta(ChatSerializer.Meta):
        fields = ChatSerializer.Meta.fields + ['participants']
