"""JWT decode helpers shared by API routes (no Argon2 import — avoids heavy auth stack)."""

from __future__ import annotations

import os
import uuid
from typing import Any

import jwt


def jwt_secret() -> str:
    secret = os.getenv("JWT_SECRET", "").strip()
    env = os.getenv("ENVIRONMENT", "development").lower()
    if not secret:
        if env in ("production", "staging"):
            raise RuntimeError("JWT_SECRET must be set when ENVIRONMENT is production or staging")
        return "dev-only-change-me-jwt-secret-min-32-chars!!"
    if len(secret) < 32:
        raise ValueError("JWT_SECRET should be at least 32 characters")
    return secret


def decode_bearer_token(authorization: str | None) -> dict[str, Any] | None:
    """Return JWT claims dict or None."""
    if not authorization or not authorization.lower().startswith("bearer "):
        return None
    raw = authorization.split(None, 1)[1].strip()
    try:
        return jwt.decode(raw, jwt_secret(), algorithms=["HS256"])  # type: ignore[no-any-return]
    except jwt.PyJWTError:
        return None


def decode_access_token_user_id(authorization: str | None) -> uuid.UUID | None:
    payload = decode_bearer_token(authorization)
    if not payload or "sub" not in payload:
        return None
    try:
        return uuid.UUID(str(payload["sub"]))
    except ValueError:
        return None


def jwt_credential_version_from_payload(payload: dict[str, Any] | None) -> int:
    """
    Credential version embedded in JWT (``cv``). Missing claim defaults to 0 so legacy
    tokens issued before ``credential_version`` match users still at version 0.
    """
    if not payload:
        return 0
    v = payload.get("cv")
    if v is None:
        return 0
    try:
        return int(v)
    except (TypeError, ValueError):
        return 0
