"""
WebSocket consumers для видеоконференций.
Обработка WebRTC signaling через Django Channels.
"""
import json
import logging
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.utils import timezone

logger = logging.getLogger(__name__)


class VideoRoomConsumer(AsyncWebsocketConsumer):
    """
    WebSocket consumer для видеокомнаты.
    Обрабатывает WebRTC signaling между участниками.
    """
    
    async def connect(self):
        """Подключение к комнате."""
        self.room_id = self.scope['url_route']['kwargs']['room_id']
        self.room_group_name = f'video_room_{self.room_id}'
        self.user = self.scope['user']
        
        # Проверка аутентификации
        if not self.user.is_authenticated:
            await self.close()
            return
        
        # Проверка доступа к комнате
        has_access = await self.check_room_access()
        if not has_access:
            await self.close()
            return
        
        # Присоединяемся к группе комнаты
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        
        await self.accept()
        
        # Отправляем подтверждение подключения
        await self.send(text_data=json.dumps({
            'type': 'connection_established',
            'message': 'Подключение установлено',
            'user_id': self.user.id
        }))
        
        # Уведомляем других участников
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'user_joined',
                'user_id': self.user.id,
                'username': self.user.get_full_name()
            }
        )
        
        # Сохраняем информацию об участнике
        await self.save_participant()
        
        logger.info(f'User {self.user.id} connected to room {self.room_id}')
    
    async def disconnect(self, close_code):
        """Отключение от комнаты."""
        if hasattr(self, 'room_group_name'):
            # Уведомляем других участников об отключении
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': 'user_left',
                    'user_id': self.user.id,
                    'username': self.user.get_full_name()
                }
            )
            
            # Покидаем группу
            await self.channel_layer.group_discard(
                self.room_group_name,
                self.channel_name
            )
            
            # Обновляем статус участника
            await self.update_participant_disconnect()
            
            logger.info(f'User {self.user.id} disconnected from room {self.room_id}')
    
    async def receive(self, text_data):
        """Получение сообщения от клиента."""
        try:
            data = json.loads(text_data)
            message_type = data.get('type')
            
            # Обработка разных типов сообщений
            if message_type == 'offer':
                await self.handle_offer(data)
            
            elif message_type == 'answer':
                await self.handle_answer(data)
            
            elif message_type == 'ice-candidate':
                await self.handle_ice_candidate(data)
            
            elif message_type == 'media-state':
                await self.handle_media_state(data)
            
            elif message_type == 'start-screen-share':
                await self.handle_screen_share(data, True)
            
            elif message_type == 'stop-screen-share':
                await self.handle_screen_share(data, False)
            
            else:
                logger.warning(f'Unknown message type: {message_type}')
        
        except json.JSONDecodeError:
            logger.error('Invalid JSON received')
        except Exception as e:
            logger.error(f'Error in receive: {str(e)}')
    
    async def handle_offer(self, data):
        """Обработка WebRTC offer."""
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'webrtc_offer',
                'offer': data.get('offer'),
                'sender_id': self.user.id
            }
        )
    
    async def handle_answer(self, data):
        """Обработка WebRTC answer."""
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'webrtc_answer',
                'answer': data.get('answer'),
                'sender_id': self.user.id
            }
        )
    
    async def handle_ice_candidate(self, data):
        """Обработка ICE candidate."""
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'ice_candidate',
                'candidate': data.get('candidate'),
                'sender_id': self.user.id
            }
        )
    
    async def handle_media_state(self, data):
        """Обработка изменения состояния медиа (вкл/выкл камера/микрофон)."""
        audio_enabled = data.get('audio_enabled')
        video_enabled = data.get('video_enabled')
        
        # Сохраняем состояние
        await self.update_participant_media_state(audio_enabled, video_enabled)
        
        # Уведомляем других участников
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'media_state_changed',
                'user_id': self.user.id,
                'audio_enabled': audio_enabled,
                'video_enabled': video_enabled
            }
        )
    
    async def handle_screen_share(self, data, is_sharing):
        """Обработка демонстрации экрана."""
        await self.update_participant_screen_sharing(is_sharing)
        
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'screen_share_changed',
                'user_id': self.user.id,
                'is_sharing': is_sharing
            }
        )
    
    # Обработчики событий от группы
    
    async def user_joined(self, event):
        """Пользователь присоединился."""
        if event['user_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'user_joined',
                'user_id': event['user_id'],
                'username': event['username']
            }))
    
    async def user_left(self, event):
        """Пользователь покинул комнату."""
        if event['user_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'user_left',
                'user_id': event['user_id'],
                'username': event['username']
            }))
    
    async def webrtc_offer(self, event):
        """Пересылка WebRTC offer."""
        if event['sender_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'offer',
                'offer': event['offer'],
                'sender_id': event['sender_id']
            }))
    
    async def webrtc_answer(self, event):
        """Пересылка WebRTC answer."""
        if event['sender_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'answer',
                'answer': event['answer'],
                'sender_id': event['sender_id']
            }))
    
    async def ice_candidate(self, event):
        """Пересылка ICE candidate."""
        if event['sender_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'ice-candidate',
                'candidate': event['candidate'],
                'sender_id': event['sender_id']
            }))
    
    async def media_state_changed(self, event):
        """Изменение состояния медиа."""
        if event['user_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'media-state-changed',
                'user_id': event['user_id'],
                'audio_enabled': event['audio_enabled'],
                'video_enabled': event['video_enabled']
            }))
    
    async def screen_share_changed(self, event):
        """Изменение демонстрации экрана."""
        if event['user_id'] != self.user.id:
            await self.send(text_data=json.dumps({
                'type': 'screen-share-changed',
                'user_id': event['user_id'],
                'is_sharing': event['is_sharing']
            }))
    
    # Работа с базой данных
    
    @database_sync_to_async
    def check_room_access(self):
        """Проверка доступа к комнате."""
        from .models import VideoRoom
        try:
            room = VideoRoom.objects.get(room_id=self.room_id)
            # Проверяем что пользователь - участник
            return self.user in [room.mentor, room.client]
        except VideoRoom.DoesNotExist:
            return False
    
    @database_sync_to_async
    def save_participant(self):
        """Сохранение информации об участнике."""
        from .models import VideoRoom, VideoParticipant
        try:
            room = VideoRoom.objects.get(room_id=self.room_id)
            participant, created = VideoParticipant.objects.get_or_create(
                room=room,
                user=self.user,
                defaults={
                    'is_connected': True,
                    'connection_id': self.channel_name
                }
            )
            
            if not created:
                participant.is_connected = True
                participant.reconnection_count += 1
                participant.save()
            
            # Отмечаем что участник подключился
            room.mark_participant_joined(self.user)
            
            # Если оба подключились и комната в ожидании, начинаем
            if room.both_joined and room.status == 'waiting':
                room.start()
        
        except Exception as e:
            logger.error(f'Error saving participant: {str(e)}')
    
    @database_sync_to_async
    def update_participant_disconnect(self):
        """Обновление при отключении участника."""
        from .models import VideoRoom, VideoParticipant
        try:
            room = VideoRoom.objects.get(room_id=self.room_id)
            participant = VideoParticipant.objects.get(room=room, user=self.user)
            participant.disconnect()
        except Exception as e:
            logger.error(f'Error updating participant disconnect: {str(e)}')
    
    @database_sync_to_async
    def update_participant_media_state(self, audio_enabled, video_enabled):
        """Обновление состояния медиа участника."""
        from .models import VideoRoom, VideoParticipant
        try:
            room = VideoRoom.objects.get(room_id=self.room_id)
            participant = VideoParticipant.objects.get(room=room, user=self.user)
            
            if audio_enabled is not None:
                participant.is_audio_enabled = audio_enabled
            if video_enabled is not None:
                participant.is_video_enabled = video_enabled
            
            participant.save()
        except Exception as e:
            logger.error(f'Error updating media state: {str(e)}')
    
    @database_sync_to_async
    def update_participant_screen_sharing(self, is_sharing):
        """Обновление демонстрации экрана."""
        from .models import VideoRoom, VideoParticipant
        try:
            room = VideoRoom.objects.get(room_id=self.room_id)
            participant = VideoParticipant.objects.get(room=room, user=self.user)
            participant.is_screen_sharing = is_sharing
            participant.save()
        except Exception as e:
            logger.error(f'Error updating screen sharing: {str(e)}')

