"""Session management for GQLDB Python driver."""

from __future__ import annotations

import threading
import time
from dataclasses import dataclass, field
from typing import List, Optional


@dataclass
class Session:
    """Represents an authenticated session with a GQLDB server."""
    id: int
    server_version: str
    roles: List[str] = field(default_factory=list)
    default_graph: str = ""
    created_at: float = field(default_factory=time.time)
    last_activity: float = field(default_factory=time.time)
    is_cluster: bool = False
    cluster_id: str = ""
    partition_count: int = 0
    _lock: threading.RLock = field(default_factory=threading.RLock, repr=False)

    def has_role(self, role: str) -> bool:
        """Check if the session has a specific role.

        Args:
            role: Role name to check.

        Returns:
            True if the session has the role.
        """
        with self._lock:
            return role in self.roles

    def idle_duration(self) -> float:
        """Return how long the session has been idle in seconds.

        Returns:
            Idle duration in seconds.
        """
        with self._lock:
            return time.time() - self.last_activity

    def age(self) -> float:
        """Return how long the session has been active in seconds.

        Returns:
            Session age in seconds.
        """
        with self._lock:
            return time.time() - self.created_at


class SessionManager:
    """Manages sessions for the client."""

    def __init__(self):
        self._session: Optional[Session] = None
        self._lock = threading.RLock()

    def login(
        self,
        session_id: int,
        server_version: str,
        roles: List[str],
        default_graph: str,
        is_cluster: bool = False,
        cluster_id: str = "",
        partition_count: int = 0
    ) -> Session:
        """Create a new session.

        Args:
            session_id: Session ID from the server.
            server_version: Server version string.
            roles: List of roles assigned to the user.
            default_graph: Default graph name.
            is_cluster: Whether the server is a cluster.
            cluster_id: Cluster ID if in cluster mode.
            partition_count: Number of partitions in cluster.

        Returns:
            The created Session.
        """
        with self._lock:
            self._session = Session(
                id=session_id,
                server_version=server_version,
                roles=roles,
                default_graph=default_graph,
                is_cluster=is_cluster,
                cluster_id=cluster_id,
                partition_count=partition_count
            )
            return self._session

    def logout(self) -> None:
        """Clear the current session."""
        with self._lock:
            self._session = None

    def get_session(self) -> Optional[Session]:
        """Return the current session.

        Returns:
            Current Session or None.
        """
        with self._lock:
            return self._session

    def get_session_id(self) -> int:
        """Return the current session ID.

        Returns:
            Session ID or 0 if not logged in.
        """
        with self._lock:
            return self._session.id if self._session else 0

    def is_logged_in(self) -> bool:
        """Check if there is an active session.

        Returns:
            True if logged in.
        """
        with self._lock:
            return self._session is not None

    def update_activity(self) -> None:
        """Update the last activity time of the session."""
        with self._lock:
            if self._session:
                self._session.last_activity = time.time()

    def set_default_graph(self, graph: str) -> None:
        """Set the default graph for the session.

        Args:
            graph: Graph name.
        """
        with self._lock:
            if self._session:
                self._session.default_graph = graph

    def get_default_graph(self) -> str:
        """Return the default graph for the session.

        Returns:
            Default graph name or empty string.
        """
        with self._lock:
            return self._session.default_graph if self._session else ""
