from __future__ import annotations

import time
import uuid
from typing import Dict, Any, Optional

from .base import StateService
from .interfaces import SessionService


# Session TTL: 8 hours
SESSION_TTL_SECONDS = 60 * 60 * 8


class SessionManager(StateService):
    """Session management service.
    
    Manages user sessions with automatic TTL-based cleanup.
    Thread-safe with in-memory storage.
    """
    
    def __init__(self, ttl_seconds: int = SESSION_TTL_SECONDS) -> None:
        """Initialize session manager.
        
        Args:
            ttl_seconds: Session time-to-live in seconds
        """
        super().__init__()
        self._ttl_seconds = ttl_seconds
    
    def new_session_id(self) -> str:
        """Create a new session ID.
        
        Returns:
            Unique session identifier
        """
        return uuid.uuid4().hex
    
    def touch_session(self, session_id: str) -> Dict[str, Any]:
        """Update session last access time.
        
        Args:
            session_id: Session identifier
            
        Returns:
            Session state dictionary
        """
        now = time.time()
        state = self.get_state(session_id)
        state["updated"] = now
        return state
    
    def get_session(self, session_id: Optional[str]) -> Dict[str, Any]:
        """Get or create session state.
        
        Args:
            session_id: Session identifier (creates new if None)
            
        Returns:
            Session state dictionary
        """
        if not session_id:
            session_id = self.new_session_id()
        return self.touch_session(session_id)
    
    def set_value(self, session_id: str, key: str, value: Any) -> None:
        """Set a value in session state.
        
        Args:
            session_id: Session identifier
            key: State key
            value: Value to store
        """
        self.touch_session(session_id)[key] = value
    
    def get_value(self, session_id: str, key: str, default: Any = None) -> Any:
        """Get a value from session state.
        
        Args:
            session_id: Session identifier
            key: State key
            default: Default value if key not found
            
        Returns:
            Stored value or default
        """
        return self.touch_session(session_id).get(key, default)
    
    def _initialize_state(self, key: str) -> Dict[str, Any]:
        """Initialize state for a new session.
        
        Args:
            key: Session ID
            
        Returns:
            Initial session state
        """
        now = time.time()
        return {"created": now, "updated": now}
    
    def _should_cleanup(self, key: str, state: Dict[str, Any]) -> bool:
        """Check if session should be cleaned up.
        
        Args:
            key: Session ID
            state: Session state
            
        Returns:
            True if session is expired
        """
        now = time.time()
        updated = state.get("updated", 0)
        return (now - updated) > self._ttl_seconds


# Global session manager instance
_session_manager: Optional[SessionManager] = None


def _get_manager() -> SessionManager:
    """Get or create global session manager instance.
    
    Returns:
        SessionManager instance
    """
    global _session_manager
    if _session_manager is None:
        _session_manager = SessionManager()
    return _session_manager


# Backward-compatible function API
def new_sid() -> str:
    """Create a new session ID.
    
    Returns:
        Unique session identifier
    """
    return _get_manager().new_session_id()


def touch_session(sid: str) -> Dict[str, Any]:
    """Update session last access time.
    
    Args:
        sid: Session identifier
        
    Returns:
        Session state dictionary
    """
    return _get_manager().touch_session(sid)


def get_session(sid: Optional[str]) -> Dict[str, Any]:
    """Get or create session state.
    
    Args:
        sid: Session identifier (creates new if None)
        
    Returns:
        Session state dictionary
    """
    return _get_manager().get_session(sid)


def set_session_value(sid: str, key: str, value: Any) -> None:
    """Set a value in session state.
    
    Args:
        sid: Session identifier
        key: State key
        value: Value to store
    """
    _get_manager().set_value(sid, key, value)


def get_session_value(sid: str, key: str, default: Any = None) -> Any:
    """Get a value from session state.
    
    Args:
        sid: Session identifier
        key: State key
        default: Default value if key not found
        
    Returns:
        Stored value or default
    """
    return _get_manager().get_value(sid, key, default)


def cleanup_expired() -> int:
    """Clean up expired sessions.
    
    Returns:
        Number of sessions cleaned up
    """
    return _get_manager().cleanup_state()


class _SessionsProxy:
    """Dict-like proxy exposing internal session state — for test isolation only."""
    def clear(self) -> None:
        _get_manager()._state.clear()

    def get(self, key: str, default: Any = None) -> Any:
        return _get_manager()._state.get(key, default)

    def pop(self, key: str, *args: Any) -> Any:
        return _get_manager()._state.pop(key, *args)


_SESSIONS = _SessionsProxy()
