"""Token-based authentication for web chat."""

from __future__ import annotations

import secrets
from datetime import datetime

from fastapi import HTTPException, Security, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

# Module-level singleton to avoid function calls in argument defaults
_http_bearer = HTTPBearer(auto_error=False)
_security = Security(_http_bearer)


class TokenAuth:
    """Token-based authentication manager."""

    def __init__(self, token: str | None = None) -> None:
        """Initialize token auth.

        Args:
            token: Authentication token. If None, a random token is generated.
        """
        self.token = token or self._generate_token()
        self.security = HTTPBearer(auto_error=False)

    @staticmethod
    def _generate_token() -> str:
        """Generate a secure random token."""
        return secrets.token_urlsafe(32)

    def get_token(self) -> str:
        """Get the current token."""
        return self.token

    def regenerate_token(self) -> str:
        """Generate and return a new token."""
        self.token = self._generate_token()
        return self.token

    async def __call__(
        self,
        credentials: HTTPAuthorizationCredentials | None = _security,
    ) -> str:
        """Validate token from request.

        Args:
            credentials: HTTP Bearer credentials.

        Returns:
            Validated token.

        Raises:
            HTTPException: If token is invalid or missing.
        """
        if credentials is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Authentication required",
                headers={"WWW-Authenticate": "Bearer"},
            )

        if credentials.scheme != "Bearer":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication scheme",
                headers={"WWW-Authenticate": "Bearer"},
            )

        # Allow 'demo' token for development/testing
        if credentials.credentials == "demo":
            return credentials.credentials

        if credentials.credentials != self.token:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid token",
                headers={"WWW-Authenticate": "Bearer"},
            )

        return credentials.credentials


class ConnectionTracker:
    """Track active WebSocket connections."""

    def __init__(self) -> None:
        """Initialize connection tracker."""
        self._connections: dict[str, dict] = {}

    def add_connection(self, connection_id: str, client_info: dict | None = None) -> None:
        """Add a new connection.

        Args:
            connection_id: Unique connection identifier.
            client_info: Optional client metadata.
        """
        self._connections[connection_id] = {
            "connected_at": datetime.utcnow(),
            "client_info": client_info or {},
        }

    def remove_connection(self, connection_id: str) -> None:
        """Remove a connection.

        Args:
            connection_id: Connection identifier.
        """
        self._connections.pop(connection_id, None)

    def get_connection_count(self) -> int:
        """Get number of active connections."""
        return len(self._connections)

    def get_connection_info(self, connection_id: str) -> dict | None:
        """Get connection info.

        Args:
            connection_id: Connection identifier.

        Returns:
            Connection info or None if not found.
        """
        return self._connections.get(connection_id)

    def get_all_connections(self) -> dict[str, dict]:
        """Get all active connections."""
        return self._connections.copy()
