"""FastMCP integration — TokenVerifier-based auth provider."""

import asyncio

from ._config import AuthConfig
from ._verifier import AuthenticationError, AuthVerifier

try:
    from fastmcp.server.auth import AccessToken, TokenVerifier

    _HAS_FASTMCP = True
except ImportError:  # pragma: no cover
    _HAS_FASTMCP = False

    class TokenVerifier:  # type: ignore[no-redef]
        """Stub so the module is importable without fastmcp."""

        def __init__(self, *args, **kwargs): ...

    class AccessToken:  # type: ignore[no-redef]
        pass


class FastMCPAuthProvider(TokenVerifier):
    """Auth provider for FastMCP servers.

    Usage::

        from remem.auth import AuthConfig, FastMCPAuthProvider

        config = AuthConfig()
        mcp = FastMCP("my-server", auth=FastMCPAuthProvider(config))
    """

    def __init__(self, config: AuthConfig):
        super().__init__()
        self._verifier = AuthVerifier(config)
        self._verify_exp = config.verify_exp

    async def verify_token(self, token: str) -> AccessToken | None:  # type: ignore[override]
        if not self._verifier.auth_enabled:
            return None

        if not token:
            return None

        try:
            user = await asyncio.to_thread(self._verifier.verify_token, token)
        except AuthenticationError:
            return None

        scopes = _extract_scopes(user.claims)
        expires_at = (
            int(user.claims["exp"])
            if self._verify_exp and "exp" in user.claims
            else None
        )

        return AccessToken(
            token=token,
            client_id=user.subject,
            scopes=scopes,
            expires_at=expires_at,
            claims=user.claims,
        )


def _extract_scopes(claims: dict) -> list[str]:
    """Extract scopes from JWT claims.

    Supports ``scope`` (space-separated string) and ``scp`` (list).
    """
    scope = claims.get("scope")
    if isinstance(scope, str):
        return scope.split()

    scp = claims.get("scp")
    if isinstance(scp, list):
        return [str(s) for s in scp]

    return []
