"""
JWT & MWT Server Functions

Token operations exposed as mizan server functions.
Works over WebSocket RPC (primary) or HTTP fallback.
"""

from django.http import HttpRequest
from pydantic import BaseModel

from mizan.client import client
from mizan.jwt.tokens import create_token_pair, refresh_tokens
from mizan_core.mwt import create_mwt


class TokenPairOutput(BaseModel):
    """JWT token pair response."""

    access_token: str
    refresh_token: str
    expires_in: int


class JWTError(BaseModel):
    """JWT operation error."""

    error: str


@client
def jwt_obtain(request: HttpRequest) -> TokenPairOutput:
    """
    Obtain JWT tokens from an authenticated session.

    Requires session authentication (cookie or WebSocket session).
    Returns access and refresh tokens that can be used for stateless auth.

    The tokens include user claims (is_staff, is_superuser) so that
    subsequent JWT-authenticated requests don't need a database query.

    Usage:
        const { access_token, refresh_token } = await call('jwt_obtain')
        // Use access_token in Authorization: Bearer header
    """
    user = request.user

    if not user.is_authenticated:
        raise PermissionError("Authentication required")

    # Get session key - for WebSocket, this comes from the scope
    session = getattr(request, "session", None)
    if session is None:
        # WebSocket request adapter - session is a dict, not SessionBase
        session_key = (
            getattr(request, "_scope", {}).get("session", {}).get("_session_key")
        )
        if not session_key:
            raise PermissionError("No session available")
    else:
        # HTTP request - ensure session is saved
        if not session.session_key:
            session.save()
        session_key = session.session_key

    # Include user claims in the token for stateless auth
    tokens = create_token_pair(
        user.pk,
        session_key,
        is_staff=getattr(user, "is_staff", False),
        is_superuser=getattr(user, "is_superuser", False),
    )

    return TokenPairOutput(
        access_token=tokens.access_token,
        refresh_token=tokens.refresh_token,
        expires_in=tokens.expires_in,
    )


@client
def jwt_refresh(request: HttpRequest, refresh_token: str) -> TokenPairOutput:
    """
    Refresh JWT tokens using a refresh token.

    Does not require session authentication - the refresh token itself
    contains the session reference and is validated against the session store.

    If the original session has been destroyed (user logged out), this fails.

    Usage:
        const { access_token, refresh_token } = await call('jwt_refresh', { refresh_token })
    """
    tokens = refresh_tokens(refresh_token)

    if tokens is None:
        raise PermissionError("Invalid or expired refresh token")

    return TokenPairOutput(
        access_token=tokens.access_token,
        refresh_token=tokens.refresh_token,
        expires_in=tokens.expires_in,
    )


# ── MWT (Mizan Web Token) ──────────────────────────────────────────────


class MWTOutput(BaseModel):
    """MWT token response."""
    token: str
    expires_in: int


@client
def mwt_obtain(request: HttpRequest) -> MWTOutput:
    """
    Obtain a Mizan Web Token from an authenticated session.

    Requires session authentication (cookie-based login).
    Returns an MWT for the X-Mizan-Token header — stateless,
    cache-aware authentication with permission staleness detection.

    Usage (from frontend):
        const { token, expires_in } = await call('mwt_obtain')
        // Use token in X-Mizan-Token header
    """
    user = request.user

    if not user.is_authenticated:
        raise PermissionError("Authentication required")

    from mizan.setup.settings import get_settings
    settings = get_settings()

    if not settings.mwt_secret:
        raise ValueError(
            "MIZAN_MWT_SECRET is not configured. MWT requires a signing secret."
        )

    token = create_mwt(user, settings.mwt_secret, ttl=settings.mwt_ttl)
    return MWTOutput(token=token, expires_in=settings.mwt_ttl)
