"""
Views для системы чата.
"""
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.db.models import Q, Max
from django.utils import timezone
from .models import Chat, ChatParticipant, Message, MessageFile
from .serializers import (
    ChatSerializer,
    ChatDetailSerializer,
    MessageSerializer,
    MessageCreateSerializer,
    ChatParticipantSerializer
)
from .permissions import IsChatParticipant
from .services import ChatService
from .utils import (
    save_file_to_preload,
    move_file_from_preload_to_chat,
    cleanup_preload_files
)


class ChatListPagination(PageNumberPagination):
    page_size = 30
    page_size_query_param = 'page_size'
    max_page_size = 100


class ChatViewSet(viewsets.ModelViewSet):
    """ViewSet для чатов."""
    
    queryset = Chat.objects.all()
    serializer_class = ChatSerializer
    permission_classes = [IsAuthenticated]
    lookup_field = 'uuid'
    pagination_class = ChatListPagination
    
    def get_queryset(self):
        """Только чаты пользователя со связанными участниками."""
        archived = self.request.query_params.get('archived', 'false').lower() == 'true'
        user = self.request.user
        
        queryset = Chat.objects.filter(
            participants__user=user,
            is_archived=archived
        )

        # Если не суперпользователь, фильтруем по связям
        if not user.is_superuser:
            from apps.users.models import User
            contact_ids = set()
            if user.role == 'mentor':
                # Студенты ментора
                contact_ids.update(User.objects.filter(role='client', client_profile__mentors=user).values_list('id', flat=True))
                # Родители студентов ментора
                contact_ids.update(User.objects.filter(role='parent', parent_profile__children__mentors=user).values_list('id', flat=True))
            elif user.role == 'client':
                # Менторы студента
                contact_ids.update(User.objects.filter(role='mentor', clients__user=user).values_list('id', flat=True))
                # Родители студента
                contact_ids.update(User.objects.filter(role='parent', parent_profile__children__user=user).values_list('id', flat=True))
            elif user.role == 'parent':
                # Менторы детей родителя
                contact_ids.update(User.objects.filter(role='mentor', clients__parents__user=user).values_list('id', flat=True))
                # Дети родителя
                contact_ids.update(User.objects.filter(role='client', client_profile__parents__user=user).values_list('id', flat=True))
            
            # Фильтруем чаты: либо групповой, либо личный со связанным пользователем
            # Для личных чатов проверяем, что второй участник (не текущий юзер) есть в списке контактов
            queryset = queryset.filter(
                Q(chat_type='group') | 
                Q(chat_type='direct', participants__user_id__in=contact_ids)
            )

        queryset = queryset.annotate(
            last_msg_time=Max('messages__created_at')
        ).select_related('created_by')
        
        # Для личных чатов нужно предзагрузить участников с их данными
        from django.db.models import Prefetch
        queryset = queryset.prefetch_related(
            Prefetch(
                'participants',
                queryset=ChatParticipant.objects.select_related('user')
            )
        )
        
        # Оптимизация: для списка prefetch только последнее сообщение вместо всех
        if self.action == 'list':
            from django.db.models import Prefetch
            queryset = queryset.prefetch_related(
                Prefetch(
                    'messages',
                    queryset=Message.objects.filter(is_deleted=False).select_related('sender').prefetch_related('files').order_by('-created_at')[:1],
                    to_attr='last_message_prefetch'
                )
            )
        else:
            # Для детального просмотра загружаем все сообщения
            queryset = queryset.prefetch_related('messages')
        
        queryset = queryset.order_by('-last_msg_time', '-created_at').distinct()
        
        # Оптимизация: для списка используем only() для ограничения полей
        if self.action == 'list':
            queryset = queryset.only(
                'id', 'uuid', 'chat_type', 'name', 'description', 'avatar',
                'created_by_id', 'lesson_id', 'messages_count', 'last_message_at',
                'is_archived', 'created_at'
            )
        
        return queryset
    
    def get_serializer_class(self):
        """Выбор сериализатора."""
        if self.action == 'retrieve':
            return ChatDetailSerializer
        return ChatSerializer
    
    @action(detail=True, methods=['get'])
    def messages(self, request, uuid=None):
        """
        Получить сообщения чата.
        
        GET /api/chat/chats/{uuid}/messages/
        """
        chat = self.get_object()
        messages = Message.objects.filter(
            chat=chat,
            is_deleted=False
        ).select_related('sender', 'reply_to', 'reply_to__sender').prefetch_related(
            'files',
            'reactions__user',
            'reads'  # Предзагружаем reads для get_is_read
        )
        
        # Сортируем по убыванию даты (последние сообщения сначала)
        # НЕ используем only() так как нужны все поля для сериализации (sender, files, reactions)
        # only() может вызвать дополнительные запросы при доступе к связанным полям
        messages = messages.order_by('-created_at')
        
        # Используем пагинацию для сообщений
        from rest_framework.pagination import PageNumberPagination
        
        paginator = PageNumberPagination()
        paginator.page_size = 30  # Размер страницы по умолчанию
        
        # Получаем параметры пагинации из запроса
        page_size = request.query_params.get('page_size', '30')
        try:
            page_size = int(page_size)
            if page_size > 0 and page_size <= 100:  # Ограничиваем максимум 100
                paginator.page_size = page_size
        except (ValueError, TypeError):
            pass
        
        # Применяем пагинацию
        page = paginator.paginate_queryset(messages, request)
        if page is not None:
            serializer = MessageSerializer(page, many=True, context={'request': request})
            return paginator.get_paginated_response(serializer.data)
        
        # Если пагинация не применилась (не должно быть), ограничиваем вручную
        limited_messages = messages[:30]
        serializer = MessageSerializer(limited_messages, many=True, context={'request': request})
        return Response({
            'count': messages.count(),
            'next': None,
            'previous': None,
            'results': serializer.data
        })
    
    @action(detail=False, methods=['post'])
    def create_direct(self, request):
        """
        Создать личный чат с пользователем.
        
        Проверяет наличие связи между пользователями.
        """
        other_user_id = request.data.get('user_id')
        
        if not other_user_id:
            return Response({
                'success': False,
                'error': 'user_id обязателен'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        # Проверяем связь
        from apps.users.models import User, Client, Parent
        try:
            other_user = User.objects.get(id=other_user_id)
        except User.DoesNotExist:
            return Response({
                'success': False,
                'error': 'Пользователь не найден'
            }, status=status.HTTP_404_NOT_FOUND)

        # Логика проверки связей
        has_connection = False
        user = request.user

        if user.role == 'mentor':
            # Ментор <-> Студент
            if other_user.role == 'client' and Client.objects.filter(user=other_user, mentors=user).exists():
                has_connection = True
            # Ментор <-> Родитель студента
            elif other_user.role == 'parent' and Parent.objects.filter(user=other_user, children__mentors=user).exists():
                has_connection = True
        
        elif user.role == 'client':
            # Студент <-> Ментор
            if other_user.role == 'mentor' and Client.objects.filter(user=user, mentors=other_user).exists():
                has_connection = True
            # Студент <-> Родитель
            elif other_user.role == 'parent' and Parent.objects.filter(user=other_user, children__user=user).exists():
                has_connection = True

        elif user.role == 'parent':
            # Родитель <-> Ментор
            if other_user.role == 'mentor' and User.objects.filter(id=other_user.id, role='mentor', clients__parents__user=user).exists():
                has_connection = True
            # Родитель <-> Ребенок
            elif other_user.role == 'client' and Client.objects.filter(user=other_user, parents__user=user).exists():
                has_connection = True

        if not has_connection and not user.is_superuser:
            return Response({
                'success': False,
                'error': 'Вы можете создавать чаты только со связанными пользователями'
            }, status=status.HTTP_403_FORBIDDEN)

        # Используем сервис для атомарного создания/получения чата
        chat, created = ChatService.get_or_create_direct_chat(
            user1=request.user,
            user2=other_user,
            created_by=request.user
        )
        
        serializer = ChatDetailSerializer(chat)
        if created:
            return Response({
                'success': True,
                'data': serializer.data
            }, status=status.HTTP_201_CREATED)
        else:
            return Response({
                'success': True,
                'data': serializer.data,
                'message': 'Чат уже существует'
            })
    
    @action(detail=True, methods=['post'])
    def mark_read(self, request, uuid=None):
        """
        Отметить сообщения как прочитанные.
        
        POST /api/chat/chats/{uuid}/mark_read/
        Body: {
            "message_uuids": ["uuid1", "uuid2", ...]  # опционально, если не указано - все сообщения
        }
        """
        chat = self.get_object()
        
        try:
            participant = chat.participants.get(user=request.user)
        except ChatParticipant.DoesNotExist:
            return Response({
                'success': False,
                'error': 'Вы не участник этого чата'
            }, status=status.HTTP_403_FORBIDDEN)
        
        # Если указаны конкретные UUID сообщений
        message_uuids = request.data.get('message_uuids', [])
        if message_uuids:
            from .models import MessageRead
            messages = Message.objects.filter(
                chat=chat,
                uuid__in=message_uuids,
                is_deleted=False
            )
            
            # Оптимизация: получаем существующие записи о прочтении одним запросом
            existing_reads = set(
                MessageRead.objects.filter(
                    message__in=messages,
                    user=request.user
                ).values_list('message_id', flat=True)
            )
            
            # Создаем только новые записи через bulk_create
            messages_list = list(messages)
            new_reads = [
                MessageRead(message=message, user=request.user)
                for message in messages_list
                if message.id not in existing_reads
            ]
            
            if new_reads:
                MessageRead.objects.bulk_create(new_reads, ignore_conflicts=True)
            
            # Собираем UUID новых прочитанных сообщений
            read_message_uuids = [
                str(message.uuid) for message in messages_list
                if message.id not in existing_reads
            ]
            
            # Отправляем уведомление через WebSocket о прочтении сообщений
            if read_message_uuids:
                from channels.layers import get_channel_layer
                from asgiref.sync import async_to_sync
                try:
                    channel_layer = get_channel_layer()
                    if channel_layer:
                        room_group_name = f'chat_{chat.uuid}'
                        async_to_sync(channel_layer.group_send)(
                            room_group_name,
                            {
                                'type': 'message_read',
                                'user_id': request.user.id,
                                'message_uuids': read_message_uuids
                            }
                        )
                except Exception as e:
                    import logging
                    logger = logging.getLogger(__name__)
                    logger.error(f"Error sending message_read via WebSocket: {e}", exc_info=True)

            # Уведомляем по WS об обновлении бейджей нижнего меню
            try:
                from apps.notifications.services import WebSocketNotificationService
                WebSocketNotificationService.send_nav_badges_updated(request.user.id)
            except Exception:
                pass
            
            # Пересчитываем непрочитанные (системные сообщения не учитываем)
            unread_count = Message.objects.filter(
                chat=chat,
                is_deleted=False
            ).exclude(
                message_type='system'
            ).exclude(
                reads__user=request.user
            ).exclude(
                sender=request.user
            ).count()
            
            participant.unread_count = unread_count
            participant.save(update_fields=['unread_count'])
        else:
            # Отмечаем все сообщения как прочитанные
            from .models import MessageRead
            messages = Message.objects.filter(
                chat=chat,
                is_deleted=False
            ).exclude(sender=request.user)
            
            # Оптимизация: получаем существующие записи о прочтении одним запросом
            messages_list = list(messages)
            existing_reads = set(
                MessageRead.objects.filter(
                    message__in=messages_list,
                    user=request.user
                ).values_list('message_id', flat=True)
            )
            
            # Создаем только новые записи через bulk_create
            new_reads = [
                MessageRead(message=message, user=request.user)
                for message in messages_list
                if message.id not in existing_reads
            ]
            
            if new_reads:
                MessageRead.objects.bulk_create(new_reads, ignore_conflicts=True)
            
            # Обновляем счетчик и время последнего прочтения
            participant.unread_count = 0
            participant.last_read_at = timezone.now()
            participant.save(update_fields=['unread_count', 'last_read_at'])

            # Уведомляем по WS об обновлении бейджей нижнего меню
            try:
                from apps.notifications.services import WebSocketNotificationService
                WebSocketNotificationService.send_nav_badges_updated(request.user.id)
            except Exception:
                pass
        
        return Response({
            'success': True,
            'message': 'Сообщения отмечены как прочитанные'
        })
    
    @action(detail=False, methods=['get', 'post'])
    def lesson_chat(self, request):
        """
        Получить или создать личный чат между участниками урока.
        
        Ищет существующий личный чат между ментором и клиентом урока.
        Если чата нет, создает новый личный чат.
        
        GET /api/chat/chats/lesson_chat/?lesson_id=123
        POST /api/chat/chats/lesson_chat/
        Body: {
            "lesson_id": 123
        }
        """
        lesson_id = request.query_params.get('lesson_id') or request.data.get('lesson_id')
        
        if not lesson_id:
            return Response({
                'success': False,
                'error': 'lesson_id обязателен'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            from apps.schedule.models import Lesson
            lesson = Lesson.objects.select_related('mentor', 'client', 'client__user').get(id=lesson_id)
        except Lesson.DoesNotExist:
            return Response({
                'success': False,
                'error': 'Урок не найден'
            }, status=status.HTTP_404_NOT_FOUND)
        
        # Определяем участников чата: ментор и клиент
        mentor = lesson.mentor
        client_user = lesson.client.user if lesson.client and lesson.client.user else None
        
        if not mentor or not client_user:
            return Response({
                'success': False,
                'error': 'У урока должны быть указаны ментор и клиент'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        # Используем сервис для атомарного создания/получения чата
        chat, created = ChatService.get_or_create_direct_chat(
            user1=mentor,
            user2=client_user,
            created_by=mentor
        )
        
        # Если текущий пользователь не участник чата (родитель), добавляем его
        if request.user != mentor and request.user != client_user:
            ChatService.ensure_participant(chat, request.user, role='member')
        
        serializer = ChatDetailSerializer(chat, context={'request': request})
        if created:
            return Response({
                'success': True,
                'data': serializer.data
            }, status=status.HTTP_201_CREATED)
        else:
            return Response({
                'success': True,
                'data': serializer.data
            })
    
    @action(detail=True, methods=['post'])
    def mark_as_read(self, request, uuid=None):
        """
        Отметить все сообщения как прочитанные (алиас для mark_read).
        
        POST /api/chat/chats/{uuid}/mark_as_read/
        """
        return self.mark_read(request, uuid)
    
    @action(detail=True, methods=['post'])
    def archive(self, request, uuid=None):
        """
        Архивировать чат.
        
        POST /api/chat/chats/{uuid}/archive/
        """
        chat = self.get_object()
        chat.is_archived = True
        chat.save()
        
        return Response({
            'success': True,
            'message': 'Чат архивирован'
        })
    
    @action(detail=True, methods=['post'])
    def unarchive(self, request, uuid=None):
        """
        Разархивировать чат.
        
        POST /api/chat/chats/{uuid}/unarchive/
        """
        chat = self.get_object()
        chat.is_archived = False
        chat.save()
        
        return Response({
            'success': True,
            'message': 'Чат разархивирован'
        })
    
    @action(detail=True, methods=['post'])
    def upload_files(self, request, uuid=None):
        """
        Предзагрузка файлов в директорию preload_file_chat{id чата}.
        
        POST /api/chat/chats/{uuid}/upload_files/
        Body: FormData с файлами
        """
        chat = self.get_object()
        
        # Проверяем доступ
        if not ChatParticipant.objects.filter(chat=chat, user=request.user).exists():
            return Response({
                'success': False,
                'error': 'У вас нет доступа к этому чату'
            }, status=status.HTTP_403_FORBIDDEN)
        
        uploaded_files = []
        errors = []
        
        # Обрабатываем все переданные файлы
        files = request.FILES.getlist('files')
        if not files:
            return Response({
                'success': False,
                'error': 'Файлы не переданы'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        for file in files:
            try:
                import uuid as uuid_lib
                import os
                # Генерируем уникальное имя файла
                ext = os.path.splitext(file.name)[1]
                unique_filename = f"{uuid_lib.uuid4()}{ext}"
                
                # Сохраняем в preload директорию
                file_path = save_file_to_preload(chat.id, file, unique_filename)
                
                uploaded_files.append({
                    'original_name': file.name,
                    'filename': unique_filename,
                    'file_path': file_path,
                    'size': file.size,
                    'content_type': file.content_type
                })
            except Exception as e:
                errors.append({
                    'filename': file.name,
                    'error': str(e)
                })
        
        return Response({
            'success': True,
            'files': uploaded_files,
            'errors': errors if errors else None
        }, status=status.HTTP_201_CREATED)


class MessageViewSet(viewsets.ModelViewSet):
    """ViewSet для сообщений."""
    
    queryset = Message.objects.all()
    serializer_class = MessageSerializer
    permission_classes = [IsAuthenticated, IsChatParticipant]
    lookup_field = 'uuid'
    
    def get_queryset(self):
        """Сообщения чата."""
        chat_uuid = self.request.query_params.get('chat')
        
        if chat_uuid:
            queryset = Message.objects.filter(
                chat__uuid=chat_uuid,
                is_deleted=False
            ).select_related('sender', 'chat', 'reply_to', 'reply_to__sender').prefetch_related(
                'files',
                'reactions__user',
                'reads'  # Предзагружаем reads для get_is_read
            )
            
            # НЕ используем only() так как нужны все поля для сериализации (sender, files, reactions)
            # only() может вызвать дополнительные запросы при доступе к связанным полям
            
            return queryset.order_by('-created_at')
        
        return Message.objects.none()
    
    def get_serializer_class(self):
        """Выбор сериализатора."""
        if self.action == 'create':
            return MessageCreateSerializer
        return MessageSerializer
    
    def create(self, request, *args, **kwargs):
        """Создание сообщения."""
        # Создаем копию данных
        data = request.data.copy()
        
        # Обрабатываем preloaded_files из FormData (QueryDict может вернуть список)
        if 'preloaded_files' in data:
            preloaded_files = data.get('preloaded_files')
            # Если это список (из QueryDict), берем первый элемент (строку JSON)
            if isinstance(preloaded_files, list) and len(preloaded_files) > 0:
                data['preloaded_files'] = preloaded_files[0]
            # Если это уже строка, оставляем как есть
            elif not isinstance(preloaded_files, str):
                data['preloaded_files'] = ''
        
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        
        # Создаем сообщение (sender уже устанавливается в сериализаторе)
        message = serializer.save()
        
        # Отправляем уведомления
        from apps.notifications.services import NotificationService
        NotificationService.send_message_notification(message)
        
        # Отправляем сообщение через WebSocket
        from channels.layers import get_channel_layer
        from asgiref.sync import async_to_sync
        from .serializers import MessageSerializer
        
        try:
            channel_layer = get_channel_layer()
            if channel_layer:
                # Сериализуем сообщение для отправки через WebSocket
                message_serializer = MessageSerializer(message, context={'request': request})
                message_data = message_serializer.data
                
                # Отправляем в группу чата
                room_group_name = f'chat_{message.chat.uuid}'
                async_to_sync(channel_layer.group_send)(
                    room_group_name,
                    {
                        'type': 'chat_message',
                        'message': message_data
                    }
                )
                # Уведомляем других участников чата об обновлении бейджей
                from apps.notifications.services import WebSocketNotificationService
                from .models import ChatParticipant
                for p in ChatParticipant.objects.filter(chat=message.chat).exclude(user=request.user).select_related('user'):
                    WebSocketNotificationService.send_nav_badges_updated(p.user.id)
        except Exception as e:
            # Логируем ошибку, но не прерываем создание сообщения
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Error sending message via WebSocket: {e}", exc_info=True)
        
        # Возвращаем полные данные сообщения
        output_serializer = MessageSerializer(message, context={'request': request})
        
        return Response({
            'success': True,
            'data': output_serializer.data
        }, status=status.HTTP_201_CREATED)
    
    def update(self, request, *args, **kwargs):
        """Редактирование сообщения."""
        message = self.get_object()
        
        # Проверяем что пользователь - отправитель
        if message.sender != request.user:
            return Response({
                'success': False,
                'error': 'Вы можете редактировать только свои сообщения'
            }, status=status.HTTP_403_FORBIDDEN)
        
        serializer = self.get_serializer(message, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        
        # Отмечаем как отредактированное
        message.mark_as_edited()
        
        return Response({
            'success': True,
            'data': serializer.data
        })
    
    def destroy(self, request, *args, **kwargs):
        """Удаление сообщения."""
        message = self.get_object()
        
        # Проверяем что пользователь - отправитель
        if message.sender != request.user:
            return Response({
                'success': False,
                'error': 'Вы можете удалять только свои сообщения'
            }, status=status.HTTP_403_FORBIDDEN)
        
        # Мягкое удаление
        message.soft_delete()
        
        return Response({
            'success': True,
            'message': 'Сообщение удалено'
        }, status=status.HTTP_204_NO_CONTENT)
    
    @action(detail=True, methods=['post'])
    def react(self, request, uuid=None):
        """
        Добавить реакцию на сообщение.
        
        POST /api/chat/messages/{uuid}/react/
        Body: {
            "emoji": "👍"
        }
        """
        message = self.get_object()
        emoji = request.data.get('emoji')
        
        if not emoji:
            return Response({
                'success': False,
                'error': 'emoji обязателен'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        from .models import MessageReaction
        
        # Создаем или удаляем реакцию
        reaction, created = MessageReaction.objects.get_or_create(
            message=message,
            user=request.user,
            emoji=emoji
        )
        
        if not created:
            # Если уже есть такая реакция, удаляем
            reaction.delete()
            return Response({
                'success': True,
                'message': 'Реакция удалена'
            })
        
        return Response({
            'success': True,
            'message': 'Реакция добавлена'
        }, status=status.HTTP_201_CREATED)
