from channels.generic.websocket import AsyncWebsocketConsumer
import json
import asyncio
from ..models import QuizGame, QuizGameParticipant
from channels.db import database_sync_to_async
import redis

# Dictionary to track inactive check tasks and active connections per game
game_check_tasks = {}
game_connections = {}

class LobbyConsumer(AsyncWebsocketConsumer):

    r = redis.Redis(host='localhost', port=6380, db=0, decode_responses=True)

    async def connect(self):
        self.join_code = self.scope['url_route']['kwargs']['join_code']
        self.room_group_name = f'lobby_{self.join_code}'
        
        # Get participant ID from session
        self.participant_id = self.scope['session'].get('participant_id')

        # Track connection
        if self.join_code not in game_connections:
            game_connections[self.join_code] = set()
        game_connections[self.join_code].add(self.channel_name)

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

        # Send initial participants list
        await self.update_participants()

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

        # Remove from connection tracking
        if self.join_code in game_connections:
            game_connections[self.join_code].discard(self.channel_name)
            if not game_connections[self.join_code]:
                # Last connection closed
                del game_connections[self.join_code]
                if self.join_code in game_check_tasks:
                    # Cancel the inactive check task
                    game_check_tasks[self.join_code].cancel()
                    del game_check_tasks[self.join_code]

    async def receive(self, text_data):
        data = json.loads(text_data)
        message_type = data.get('type')
        print(f'Received message type: {message_type}')

        if message_type == 'ping':
            # Respond with pong to keep connection alive
            await self.send(text_data=json.dumps({
                'type': 'pong'
            }))
            return

        elif message_type in ['leave_game', 'kick_player']:
            participant_id = data.get('participant_id')
            if participant_id:
                try:
                    # Get participant info before deletion
                    participant = await database_sync_to_async(QuizGameParticipant.objects.get)(participant_id=participant_id)
                    display_name = participant.display_name
                    
                    # For kick_player, verify that the request comes from the host
                    if message_type == 'kick_player':
                        game = await database_sync_to_async(lambda: participant.quiz_game)()
                        # Get host_id from message
                        host_id = data.get('host_id')
                        print(f'Kick attempt - Game host_id: {game.host_id}, Message host_id: {host_id}')
                        if not host_id:
                            print('No host_id in message')
                            return
                        if str(game.host_id) != str(host_id):
                            print(f'Host ID mismatch: {game.host_id} != {host_id}')
                            return
                        
                        # Also verify against cookie as backup
                        cookie_host_id = self.scope.get('cookies', {}).get('host_id')
                        if not cookie_host_id or str(cookie_host_id) != str(host_id):
                            print(f'Cookie host_id mismatch: {cookie_host_id} != {host_id}')
                            return
                    
                    # Delete the participant
                    await database_sync_to_async(participant.delete)()
                    
                    # Notify other players
                    await self.channel_layer.group_send(
                        self.room_group_name,
                        {
                            'type': 'player_left',
                            'player_name': display_name,
                            'was_kicked': message_type == 'kick_player',
                            'participant_id': participant_id
                        }
                    )
                    
                    # Update participants list
                    await self.update_participants()
                    
                    # If it's the kicked player's connection, send them home
                    if participant_id == self.participant_id:
                        await self.send(text_data=json.dumps({
                            'type': 'redirect',
                            'url': '/'
                        }))
                except QuizGameParticipant.DoesNotExist:
                    pass
        elif message_type == 'update_participants':
            await self.update_participants()
        elif message_type == 'start_game':
            host_id = data.get('host_id')
            if host_id:
                success = await self.start_game(host_id)
                if success:
                    await self.channel_layer.group_send(
                        self.room_group_name,
                        {
                            'type': 'game_state_update',
                            'action': 'start_game',
                            'redirect_url': f'/play/game/{self.join_code}/question'
                        }
                    )

    async def get_participants_list(self):
        try:
            from django.utils import timezone
            from datetime import timedelta
            game = await database_sync_to_async(QuizGame.objects.get)(join_code=self.join_code)
            participants = await database_sync_to_async(lambda: list(
                game.participants
                .values('participant_id', 'display_name')
            ))()

            
            # Zustand laden
            try:
                r = redis.Redis(host='localhost', port=6380, db=0, decode_responses=True)

                # Alte Teilnehmer aus Redis holen
                data = r.get(f"last_participants_{self.room_group_name}")
                prev_names = set(json.loads(data)) if data else set()

                # Aktuelle Teilnehmer aus dem Argument extrahieren
                current_names = set(p['display_name'] for p in participants)

                # Neue Teilnehmer bestimmen
                new_participants = current_names - prev_names

                # Benachrichtigung für neue Teilnehmer versenden
                for name in new_participants:
                    await self.channel_layer.group_send(
                        self.room_group_name,
                        {
                            'type': 'player_joined',
                            'player_name': name
                        }
                    )

                # Teilnehmerliste in Redis aktualisieren
                r.set(f"last_participants_{self.room_group_name}", json.dumps(list(current_names)))

            except Exception as e:
                print(f"Error in send_join_notifications: {e}")
            self.last_participants = participants
            return participants
        except QuizGame.DoesNotExist:
            return []

    async def update_participants(self):
        participants = await self.get_participants_list()
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'participants_list_update',
                'participants': participants
            }
        )

    async def participants_list_update(self, event):
        await self.send(text_data=json.dumps({
            'type': 'participants_list_update',
            'participants': event['participants']
        }))

    @database_sync_to_async
    def start_game(self, host_id):
        try:
            game = QuizGame.objects.get(join_code=self.join_code)
            if str(game.host_id) == str(host_id):
                from django.utils import timezone
                game.current_state = 'question'
                game.question_start_time = timezone.now()
                game.save()
                return True
        except QuizGame.DoesNotExist:
            pass
        return False

    async def game_state_update(self, event):
        await self.send(text_data=json.dumps({
            'type': 'game_state_update',
            'action': event['action'],
            'redirect_url': event.get('redirect_url')
        }))

    async def player_joined(self, event):
        await self.send(text_data=json.dumps({
            'type': 'player_joined',
            'player_name': event['player_name']
        }))

    async def player_left(self, event):
        message = {
            'type': 'player_left',
            'player_name': event['player_name'],
            'was_kicked': event.get('was_kicked', False)
        }
        if event.get('was_kicked') and event.get('participant_id'):
            message['participant_id'] = event['participant_id']
        await self.send(text_data=json.dumps(message))


