"""
ElevenLabs Connection Limiter
Limits concurrent ElevenLabs WebSocket connections to prevent exceeding workspace limits.
"""

import asyncio
from typing import Optional
from services.log_utils import Log


class ElevenLabsConnectionLimiter:
    """
    Singleton connection limiter for ElevenLabs WebSocket connections.
    Limits concurrent connections to prevent exceeding workspace subscription limits.
    
    Workspace limit: 6 (base) or 14 (with bursting enabled)
    Agent limit: 14 concurrent calls
    Recommended limit: 14 (matches agent limit)
    """
    _instance: Optional['ElevenLabsConnectionLimiter'] = None
    _lock = asyncio.Lock()
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            # Set to agent limit (14) - adjust if workspace limit is different
            cls._instance.max_connections = 30
            cls._instance.semaphore = asyncio.Semaphore(30)
            cls._instance.active_connections = 0
            cls._instance.connection_map: dict[str, bool] = {}  # Track which sessions have connections
        return cls._instance
    
    async def acquire(self, session_id: str, timeout: float = 5.0) -> bool:
        """
        Acquire a connection slot for a session.
        
        Args:
            session_id: Unique session identifier
            timeout: Maximum time to wait for a slot (seconds)
        
        Returns:
            True if slot acquired, False if timeout or limit reached
        """
        try:
            # Try to acquire semaphore with timeout
            acquired = await asyncio.wait_for(
                self.semaphore.acquire(),
                timeout=timeout
            )
            
            if acquired:
                    async with self._lock:
                        self.active_connections += 1
                        self.connection_map[session_id] = True
            return True
        except asyncio.TimeoutError:
            Log.warning(
                f"⚠️ ElevenLabs connection limit reached ({self.max_connections}). "
                f"Timeout waiting for slot for session {session_id}"
            )
            return False
        except Exception as e:
            Log.error(f"❌ Error acquiring connection slot for {session_id}: {e}")
            return False
    
    async def release(self, session_id: str) -> None:
        """
        Release a connection slot for a session.
        
        Args:
            session_id: Unique session identifier
        """
        if session_id in self.connection_map:
                self.semaphore.release()
                async with self._lock:
                    self.active_connections = max(0, self.active_connections - 1)
                    del self.connection_map[session_id]
            # Attempted to release non-existent connection (expected in some cases)
    
    def get_active_count(self) -> int:
        """Get current number of active connections."""
        return self.active_connections
    
    def get_available_slots(self) -> int:
        """Get number of available connection slots."""
        return self.max_connections - self.active_connections


# Global instance
elevenlabs_limiter = ElevenLabsConnectionLimiter()

