from __future__ import annotations
import asyncio
import time
from dataclasses import dataclass, field
from typing import Any, Optional, Callable

from .phase import PhaseMachine

@dataclass
class Session:
    session_id: str
    game_name: str
    guild_id: int
    channel_id: int
    host_id: int
    created_at: float
    ended: bool = False

    meta: dict[str, Any] = field(default_factory=dict)

    # Concurrency
    session_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
    user_locks: dict[int, asyncio.Lock] = field(default_factory=dict)

    # Phase management
    phases: PhaseMachine = field(default_factory=lambda: PhaseMachine("lobby"))

    def get_user_lock(self, user_id: int) -> asyncio.Lock:
        lock = self.user_locks.get(user_id)
        if lock is None:
            lock = asyncio.Lock()
            self.user_locks[user_id] = lock
        return lock

class SessionManager:
    """
    One session per (guild, channel, game_name).
    Thread-safe with global lock.
    """
    def __init__(self):
        self._sessions: dict[str, Session] = {}
        self._lock = asyncio.Lock()

    @staticmethod
    def _key(guild_id: int, channel_id: int, game_name: str) -> str:
        return f"{guild_id}:{channel_id}:{game_name}"

    async def create(
        self,
        guild_id: int,
        channel_id: int,
        host_id: int,
        game_name: str,
        session_id_factory: Callable[[], str],
    ) -> tuple[Optional[Session], str]:
        key = self._key(guild_id, channel_id, game_name)
        async with self._lock:
            existing = self._sessions.get(key)
            if existing and not existing.ended:
                return None, "يوجد جلسة نشطة بالفعل في هذه القناة!"
            sess = Session(
                session_id=session_id_factory(),
                game_name=game_name,
                guild_id=guild_id,
                channel_id=channel_id,
                host_id=host_id,
                created_at=time.monotonic(),
            )
            self._sessions[key] = sess
            return sess, "✅ تم إنشاء الجلسة"

    def get(self, guild_id: int, channel_id: int, game_name: str) -> Optional[Session]:
        return self._sessions.get(self._key(guild_id, channel_id, game_name))

    async def end(self, guild_id: int, channel_id: int, game_name: str):
        key = self._key(guild_id, channel_id, game_name)
        async with self._lock:
            sess = self._sessions.pop(key, None)
            if sess:
                sess.ended = True
                await sess.phases.cancel()

    async def cleanup_stale(self, max_age_seconds: int = 7200):
        now = time.monotonic()
        async with self._lock:
            stale = [k for k, s in self._sessions.items() if (now - s.created_at) > max_age_seconds]
            for k in stale:
                sess = self._sessions.pop(k, None)
                if sess:
                    sess.ended = True
                    await sess.phases.cancel()