import asyncio
import uuid
import httpx
import logging
from typing import Optional, Dict, Any, List
from .profile import local_profile
from runtime.config import load_config
from runtime.identity import Identity

logger = logging.getLogger("brynq.rooms.manager")

_config = load_config()
CLOUD_URL = _config.cloud_url  # https://api.brynq.ai in prod, overridable via env

# Shared identity instance — same one used by CLI
_identity = Identity(cloud_url=CLOUD_URL)


class RoomManager:
    def __init__(self):
        self.active_room: Optional[Dict[str, Any]] = None
        self.is_host: bool = False
        self.host_service = None
        self.client_service = None

        # New: A2A Protocol Manager
        from .a2a import A2AManager
        self.a2a = A2AManager(self)

    def _get_local_profile(self) -> Dict[str, Any]:
        """Helper to get the current user profile."""
        return local_profile.get()

    def _get_auth_headers(self) -> Dict[str, str]:
        """Get JWT auth headers from Identity module."""
        return _identity.get_auth_headers()

    async def _ensure_auth(self) -> Dict[str, str]:
        """Ensure we have a valid JWT token via Identity module."""
        _identity.ensure_identity()
        headers = _identity.get_auth_headers()
        if headers:
            return headers
        # Identity module handles auto-registration internally
        logger.warning("Identity module has no token after ensure_identity()")
        return {}

    async def create_room(self, name: str) -> Dict[str, Any]:
        """Creates a room on the cloud, starts the local host WebSocket."""
        _identity.ensure_identity()
        host_id = _identity.user_id or str(uuid.uuid4())

        headers = await self._ensure_auth()

        async with httpx.AsyncClient() as client:
            resp = await client.post(f"{CLOUD_URL}/v1/rooms", json={
                "name": name,
                "host_id": host_id,
                "host_name": _identity.display_name,
                "host_address": "ws://localhost:8081/ws/room"
            }, headers=headers)
            resp.raise_for_status()
            room = resp.json()

        self.active_room = room
        self.is_host = True
        
        # Start the local host service
        from .room_host import RoomHost
        self.host_service = RoomHost(self)
        asyncio.create_task(self.host_service.start())
        
        return room

    async def join_room(self, code: str) -> Dict[str, Any]:
        """Joins via the cloud directory, connects to host."""
        headers = await self._ensure_auth()
        async with httpx.AsyncClient() as client:
            resp = await client.post(f"{CLOUD_URL}/v1/rooms/join", json={
                "room_code": code
            }, headers=headers)
            resp.raise_for_status()
            room = resp.json()

        self.active_room = room
        self.members = room.get("members", [])
        self.is_host = False

        # Connect client to the host
        from .room_client import RoomClient
        self.client_service = RoomClient(self, room["host_address"], room["room_id"])
        asyncio.create_task(self.client_service.connect())
        
        return room

    async def leave_room(self):
        if self.client_service:
            await self.client_service.disconnect()
            self.client_service = None
        self.active_room = None
        self.is_host = False

    async def close_room(self):
        if not self.is_host or not self.active_room:
            return
        
        headers = await self._ensure_auth()
        async with httpx.AsyncClient() as client:
            await client.delete(f"{CLOUD_URL}/v1/rooms/{self.active_room['room_id']}",
                                headers=headers)
            
        if self.host_service:
            await self.host_service.stop()
            self.host_service = None
        
        self.active_room = None
        self.is_host = False

    def send_message(self, content: str):
        if self.is_host and self.host_service:
            asyncio.create_task(self.host_service.broadcast_chat(content))
        elif not self.is_host and self.client_service:
            asyncio.create_task(self.client_service.send_chat(content))

    async def send_message_raw(self, message: Dict[str, Any]):
        """Send an arbitrary JSON message through the room WebSocket.

        Unlike send_message() which wraps content in a chat message,
        this sends the dict as-is. Used for project sync messages.
        """
        import json
        if self.is_host and self.host_service:
            asyncio.create_task(self.host_service.broadcast(message))
        elif not self.is_host and self.client_service:
            asyncio.create_task(self.client_service.ws.send(json.dumps(message)))

    # --- Presence & Social ---

    async def send_heartbeat(self, status: str = "online", models: List[str] = None, compute: Dict[str, Any] = None):
        """Send a heartbeat to the cloud presence API."""
        headers = await self._ensure_auth()
        async with httpx.AsyncClient() as client:
            await client.post(f"{CLOUD_URL}/v1/presence/heartbeat", json={
                "status": status,
                "models": models or [],
                "compute": compute or {},
                "current_room": self.active_room.get("room_id") if self.active_room else None
            }, headers=headers)

    async def get_online_users(self) -> List[Dict[str, Any]]:
        """Get online users from the cloud."""
        headers = await self._ensure_auth()
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"{CLOUD_URL}/v1/presence", headers=headers)
            resp.raise_for_status()
            return resp.json()

    async def get_friends(self) -> List[Dict[str, Any]]:
        """Get friend list from the cloud."""
        headers = await self._ensure_auth()
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"{CLOUD_URL}/v1/friends", headers=headers)
            resp.raise_for_status()
            return resp.json()

room_manager = RoomManager()
