"""
Online status tracking using Redis.
"""
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
from django.conf import settings
import json


class OnlineStatusManager:
    """
    Manages online status using Django Channels' channel layer.
    Uses Redis under the hood via channels_redis.
    """

    ONLINE_KEY_PREFIX = "online_user_"
    STATUS_EXPIRY = 300  # 5 minutes

    def __init__(self):
        self.channel_layer = get_channel_layer()

    async def set_online(self, user_id: int, channel_name: str):
        """
        Mark a user as online and store their channel name.
        """
        if self.channel_layer is None:
            return

        # Add user to their personal group for direct notifications
        await self.channel_layer.group_add(
            f"user_{user_id}",
            channel_name
        )

        # Broadcast online status to relevant users
        await self.broadcast_status(user_id, is_online=True)

    async def set_offline(self, user_id: int, channel_name: str):
        """
        Mark a user as offline.
        """
        if self.channel_layer is None:
            return

        # Remove from personal group
        await self.channel_layer.group_discard(
            f"user_{user_id}",
            channel_name
        )

        # Broadcast offline status
        await self.broadcast_status(user_id, is_online=False)

    async def broadcast_status(self, user_id: int, is_online: bool):
        """
        Broadcast user status to their conversation partners.
        """
        if self.channel_layer is None:
            return

        from chat.models import Conversation
        from asgiref.sync import sync_to_async

        # Get all conversation partner IDs
        @sync_to_async
        def get_partner_ids():
            conversations = Conversation.objects.filter(participants=user_id)
            partner_ids = set()
            for conv in conversations:
                for p in conv.participants.exclude(id=user_id):
                    partner_ids.add(p.id)
            return partner_ids

        partner_ids = await get_partner_ids()

        # Send status update to each partner's personal group
        for partner_id in partner_ids:
            await self.channel_layer.group_send(
                f"user_{partner_id}",
                {
                    "type": "user_status",
                    "user_id": user_id,
                    "is_online": is_online
                }
            )

    async def join_conversation_group(self, conversation_id, channel_name: str):
        """
        Add a channel to a conversation's group.
        """
        if self.channel_layer is None:
            return

        # Normalize ID to match frontend (hyphenless UUID)
        normalized_id = str(conversation_id).replace('-', '')
        await self.channel_layer.group_add(
            f"chat_{normalized_id}",
            channel_name
        )

    async def leave_conversation_group(self, conversation_id, channel_name: str):
        """
        Remove a channel from a conversation's group.
        """
        if self.channel_layer is None:
            return

        # Normalize ID to match frontend (hyphenless UUID)
        normalized_id = str(conversation_id).replace('-', '')
        await self.channel_layer.group_discard(
            f"chat_{normalized_id}",
            channel_name
        )


# Singleton instance
online_manager = OnlineStatusManager()
