"""
API views для интерактивной доски.
"""
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.shortcuts import get_object_or_404
from django.db import models
from .models import Board, BoardElement, BoardSnapshot
from .serializers import (
    BoardSerializer,
    BoardListSerializer,
    BoardCreateSerializer,
    BoardElementSerializer,
    BoardElementCreateSerializer,
    BoardSnapshotSerializer,
    BoardSnapshotCreateSerializer
)
from .permissions import IsBoardOwnerOrParticipant, IsBoardOwner


class BoardViewSet(viewsets.ModelViewSet):
    """
    ViewSet для управления досками.
    
    list: Список досок пользователя
    create: Создать доску
    retrieve: Получить доску с элементами
    update: Обновить доску
    destroy: Удалить доску
    join: Получить информацию для присоединения
    """
    
    permission_classes = [IsAuthenticated]
    lookup_field = 'board_id'
    
    def get_queryset(self):
        """Получение досок пользователя."""
        user = self.request.user
        
        # Фильтры из query params
        mentor_id = self.request.query_params.get('mentor')
        student_id = self.request.query_params.get('student')
        
        # Базовый queryset - доски где пользователь владелец, участник, ментор или студент
        queryset = Board.objects.filter(
            models.Q(owner=user) |
            models.Q(participants=user) |
            models.Q(mentor=user) |
            models.Q(student=user) |
            models.Q(access_type='public')
        ).distinct()
        
        # Фильтр по паре ментор-студент (для получения персональной доски)
        if mentor_id and student_id:
            queryset = queryset.filter(mentor_id=mentor_id, student_id=student_id)
        
        # Фильтр по занятию удален - доска привязана к паре mentor-student, а не к уроку
        
        queryset = queryset.select_related(
            'owner',
            'mentor',
            'student',
            'last_edited_by'
        ).prefetch_related('participants')
        
        # Оптимизация: для списка используем only() для ограничения полей
        if self.action == 'list':
            queryset = queryset.only(
                'id', 'board_id', 'title', 'description', 'owner_id', 'mentor_id',
                'student_id', 'access_type', 'is_template', 'is_active',
                'views_count', 'last_edited_by_id', 'last_edited_at',
                'created_at', 'updated_at'
            )
        
        return queryset
    
    def get_serializer_class(self):
        """Выбор сериализатора."""
        if self.action == 'list':
            return BoardListSerializer
        elif self.action == 'create':
            return BoardCreateSerializer
        return BoardSerializer
    
    def create(self, request, *args, **kwargs):
        """Создание доски."""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        board = serializer.save()
        
        # Возвращаем полную информацию
        response_serializer = BoardSerializer(board)
        return Response(
            response_serializer.data,
            status=status.HTTP_201_CREATED
        )
    
    def retrieve(self, request, *args, **kwargs):
        """Получить доску."""
        board = self.get_object()
        
        # Проверяем доступ
        if not board.has_access(request.user):
            return Response(
                {'error': 'У вас нет доступа к этой доске'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        # Увеличиваем счетчик просмотров
        board.increment_views()
        
        serializer = self.get_serializer(board)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get'])
    def join(self, request, board_id=None):
        """
        Получить информацию для присоединения к доске.
        
        GET /api/board/boards/{board_id}/join/
        """
        board = self.get_object()
        
        # Проверяем доступ
        if not board.has_access(request.user):
            return Response(
                {'error': 'У вас нет доступа к этой доске'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        # WebSocket URL
        ws_url = f"ws://{request.get_host()}/ws/board/{board.board_id}/"
        if request.is_secure():
            ws_url = f"wss://{request.get_host()}/ws/board/{board.board_id}/"
        
        # Получаем элементы доски
        elements = board.elements.filter(is_deleted=False).order_by('z_index', 'created_at')
        elements_data = BoardElementSerializer(elements, many=True).data
        
        return Response({
            'board_id': str(board.board_id),
            'ws_url': ws_url,
            'board': BoardSerializer(board).data,
            'elements': elements_data
        })
    
    @action(detail=False, methods=['get', 'post'], url_path='get-or-create-mentor-student')
    def get_or_create_mentor_student(self, request):
        """
        Одна доска на пару ментор–студент (вне зависимости от урока).
        Атомарно вернуть существующую или создать новую.
        
        GET/POST /api/board/boards/get-or-create-mentor-student/?mentor=<id>&student=<id>
        """
        from apps.users.models import User

        mentor_id = request.query_params.get('mentor') or (request.data.get('mentor') if request.data else None)
        student_id = request.query_params.get('student') or (request.data.get('student') if request.data else None)

        try:
            mentor_id = int(mentor_id) if mentor_id is not None else None
            student_id = int(student_id) if student_id is not None else None
        except (TypeError, ValueError):
            return Response(
                {'error': 'Укажите mentor и student (числовые id)'},
                status=status.HTTP_400_BAD_REQUEST
            )

        if not mentor_id or not student_id:
            return Response(
                {'error': 'Укажите mentor и student'},
                status=status.HTTP_400_BAD_REQUEST
            )

        user = request.user
        if user.id not in (mentor_id, student_id):
            return Response(
                {'error': 'Доступ только для ментора или студента этой пары'},
                status=status.HTTP_403_FORBIDDEN
            )

        mentor = get_object_or_404(User, id=mentor_id)
        student = get_object_or_404(User, id=student_id)

        board, created = Board.objects.get_or_create(
            mentor_id=mentor_id,
            student_id=student_id,
            defaults={
                'title': 'Доска для совместной работы',
                'description': 'Интерактивная доска для занятия',
                'access_type': 'mentor_student',
                'owner': mentor,
            }
        )
        if created:
            board.participants.add(mentor, student)

        serializer = BoardSerializer(board)
        return Response(serializer.data, status=status.HTTP_201_CREATED if created else status.HTTP_200_OK)

    @action(detail=False, methods=['get'])
    def my_boards(self, request):
        """
        Получить доски пользователя.
        
        GET /api/board/boards/my_boards/
        """
        boards = Board.objects.filter(owner=request.user, is_active=True)
        serializer = BoardListSerializer(boards, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'])
    def shared_with_me(self, request):
        """
        Получить доски, к которым пользователь имеет доступ.
        
        GET /api/board/boards/shared_with_me/
        """
        boards = Board.objects.filter(
            participants=request.user,
            is_active=True
        ).exclude(owner=request.user)
        serializer = BoardListSerializer(boards, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['get', 'post'])
    def tldraw(self, request, board_id=None):
        """
        Получить или сохранить Tldraw состояние.
        
        GET /api/board/boards/{board_id}/tldraw/ - получить snapshot
        POST /api/board/boards/{board_id}/tldraw/ - сохранить snapshot
        """
        board = self.get_object()
        
        # Проверяем доступ
        if not board.has_access(request.user):
            return Response(
                {'error': 'У вас нет доступа к этой доске'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        if request.method == 'GET':
            snapshot = board.tldraw_snapshot or {}
            files_count = board.get_files_count()
            elements_count = board.get_elements_count_from_snapshot()
            
            return Response({
                'board_id': str(board.board_id),
                'snapshot': snapshot,
                'stats': {
                    'files_count': files_count,
                    'elements_count': elements_count,
                }
            })
        
        elif request.method == 'POST':
            # Сохраняем новое состояние
            snapshot = request.data.get('snapshot', {})
            
            # Очищаем неиспользуемые файлы из snapshot
            if isinstance(snapshot, dict):
                elements = snapshot.get('elements', [])
                files = snapshot.get('files', {})
                
                if isinstance(files, dict) and isinstance(elements, list):
                    # Собираем все используемые fileId
                    used_file_ids = set()
                    for element in elements:
                        if isinstance(element, dict):
                            # Проверяем fileId в элементе
                            file_id = element.get('fileId')
                            if file_id and isinstance(file_id, str):
                                used_file_ids.add(file_id)
                            
                            # Проверяем все строковые значения, которые могут быть fileId
                            for value in element.values():
                                if isinstance(value, str) and value in files:
                                    used_file_ids.add(value)
                    
                    # Оставляем только используемые файлы
                    cleaned_files = {
                        file_id: file_data 
                        for file_id, file_data in files.items() 
                        if file_id in used_file_ids
                    }
                    
                    removed_count = len(files) - len(cleaned_files)
                    if removed_count > 0:
                        print(f'[BoardViewSet] Очищено {removed_count} неиспользуемых файлов')
                    
                    snapshot['files'] = cleaned_files
            
            board.tldraw_snapshot = snapshot
            board.mark_edited(request.user)
            board.save(update_fields=['tldraw_snapshot', 'last_edited_by', 'last_edited_at', 'updated_at'])
            
            # Подсчитываем файлы и элементы из snapshot
            files_count = board.get_files_count()
            elements_count = board.get_elements_count_from_snapshot()
            
            return Response({
                'success': True,
                'board_id': str(board.board_id),
                'message': 'Состояние доски сохранено',
                'stats': {
                    'files_count': files_count,
                    'elements_count': elements_count,
                }
            })
    
    @action(detail=False, methods=['get'])
    def templates(self, request):
        """
        Получить шаблоны досок.
        
        GET /api/board/boards/templates/
        """
        boards = Board.objects.filter(is_template=True, is_active=True)
        serializer = BoardListSerializer(boards, many=True)
        return Response(serializer.data)
    
    @action(detail=True, methods=['post'])
    def duplicate(self, request, board_id=None):
        """
        Дублировать доску.
        
        POST /api/board/boards/{board_id}/duplicate/
        """
        original_board = self.get_object()
        
        # Проверяем доступ
        if not original_board.has_access(request.user):
            return Response(
                {'error': 'У вас нет доступа к этой доске'},
                status=status.HTTP_403_FORBIDDEN
            )
        
        # Создаем копию доски
        new_board = Board.objects.create(
            title=f"{original_board.title} (копия)",
            description=original_board.description,
            owner=request.user,
            access_type='private',
            background_color=original_board.background_color,
            grid_enabled=original_board.grid_enabled,
            width=original_board.width,
            height=original_board.height
        )
        
        # Копируем элементы
        # Оптимизация: используем bulk_create вместо цикла с create()
        elements = list(original_board.elements.filter(is_deleted=False))
        new_elements = []
        for element in elements:
            new_elements.append(
                BoardElement(
                    board=new_board,
                    created_by=request.user,
                    element_type=element.element_type,
                    x=element.x,
                    y=element.y,
                    width=element.width,
                    height=element.height,
                    rotation=element.rotation,
                    z_index=element.z_index,
                    content=element.content,
                    font_size=element.font_size,
                    font_family=element.font_family,
                    font_weight=element.font_weight,
                    text_align=element.text_align,
                    text_color=element.text_color,
                    shape_type=element.shape_type,
                    fill_color=element.fill_color,
                    stroke_color=element.stroke_color,
                    stroke_width=element.stroke_width,
                    opacity=element.opacity,
                    image_url=element.image_url,
                    drawing_data=element.drawing_data
                )
            )
        if new_elements:
            BoardElement.objects.bulk_create(new_elements)
        
        new_board.update_elements_count()
        
        serializer = BoardSerializer(new_board)
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class BoardElementViewSet(viewsets.ModelViewSet):
    """
    ViewSet для управления элементами доски.
    
    list: Список элементов доски
    create: Создать элемент
    retrieve: Получить элемент
    update: Обновить элемент
    destroy: Удалить элемент
    """
    
    permission_classes = [IsAuthenticated, IsBoardOwnerOrParticipant]
    
    def get_queryset(self):
        """Получение элементов."""
        board_id = self.request.query_params.get('board_id')
        
        if board_id:
            queryset = BoardElement.objects.filter(
                board__board_id=board_id,
                is_deleted=False
            ).select_related('board', 'created_by', 'locked_by')
        else:
            queryset = BoardElement.objects.filter(
                is_deleted=False
            ).select_related('board', 'created_by', 'locked_by')
        
        # Оптимизация: для списка используем only() для ограничения полей
        if self.action == 'list':
            queryset = queryset.only(
                'id', 'board_id', 'element_type', 'element_data', 'position_x', 'position_y',
                'width', 'height', 'z_index', 'created_by_id', 'locked_by_id', 'is_locked',
                'is_deleted', 'created_at', 'updated_at'
            )
        
        return queryset
    
    def get_serializer_class(self):
        """Выбор сериализатора."""
        if self.action == 'create':
            return BoardElementCreateSerializer
        return BoardElementSerializer
    
    def create(self, request, *args, **kwargs):
        """Создание элемента."""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        element = serializer.save()
        
        response_serializer = BoardElementSerializer(element)
        return Response(
            response_serializer.data,
            status=status.HTTP_201_CREATED
        )
    
    def destroy(self, request, *args, **kwargs):
        """Удаление элемента (мягкое)."""
        element = self.get_object()
        element.soft_delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


class BoardSnapshotViewSet(viewsets.ModelViewSet):
    """
    ViewSet для управления снимками досок.
    
    list: Список снимков доски
    create: Создать снимок
    retrieve: Получить снимок
    destroy: Удалить снимок
    """
    
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """Получение снимков."""
        board_id = self.request.query_params.get('board_id')
        
        if board_id:
            queryset = BoardSnapshot.objects.filter(
                board__board_id=board_id
            ).select_related('board', 'created_by')
        else:
            # Снимки досок пользователя
            queryset = BoardSnapshot.objects.filter(
                board__owner=self.request.user
            ).select_related('board', 'created_by')
        
        # Оптимизация: для списка используем only() для ограничения полей
        if self.action == 'list':
            queryset = queryset.only(
                'id', 'board_id', 'snapshot_data', 'created_by_id', 'description', 'created_at'
            )
        
        return queryset.order_by('-created_at')
    
    def get_serializer_class(self):
        """Выбор сериализатора."""
        if self.action == 'create':
            return BoardSnapshotCreateSerializer
        return BoardSnapshotSerializer
    
    def create(self, request, *args, **kwargs):
        """Создание снимка."""
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        snapshot = serializer.save()
        
        response_serializer = BoardSnapshotSerializer(snapshot)
        return Response(
            response_serializer.data,
            status=status.HTTP_201_CREATED
        )
