"""JWT 签名工具（对齐 Java ``JwtUtil``，基于 PyJWT）。

HMAC-SHA256，1 小时过期；``app_secret`` 至少 32 字节。
"""

from __future__ import annotations

import time
from typing import Any, Dict

import jwt


_EXPIRATION_SECONDS = 60 * 60
_MIN_SECRET_BYTES = 32


class JwtUtil:
    EXPIRATION_SECONDS = _EXPIRATION_SECONDS

    @staticmethod
    def generate_token(app_secret: str, claims: Dict[str, Any]) -> str:
        """签发 JWT。

        :param app_secret: 至少 32 字节（HMAC-SHA256 要求 256 bit 密钥）
        :param claims: 自定义载荷，会自动附加 ``exp``
        """
        if not app_secret or len(app_secret.encode("utf-8")) < _MIN_SECRET_BYTES:
            raise ValueError(
                f"app_secret must be at least {_MIN_SECRET_BYTES} bytes for HMAC-SHA256"
            )
        payload: Dict[str, Any] = dict(claims)
        payload["exp"] = int(time.time()) + _EXPIRATION_SECONDS
        token = jwt.encode(payload, app_secret, algorithm="HS256")
        # PyJWT >=2 默认返回 str；某些极端版本返回 bytes，做一次防御
        if isinstance(token, bytes):
            token = token.decode("utf-8")
        return token

    @staticmethod
    def validate_token(app_secret: str, token: str) -> Dict[str, Any]:
        """校验 token 并返回 payload；失败时抛 ``RuntimeError("<code>")``。

        与 Java 版错误码保持一致：
            1001 过期 / 1002 不支持 / 1003 格式错误 / 1004 签名错误 / 1005 空入参
        """
        if not token:
            raise RuntimeError("1005")
        try:
            return jwt.decode(token, app_secret, algorithms=["HS256"])
        except jwt.ExpiredSignatureError as exc:
            raise RuntimeError("1001") from exc
        except jwt.InvalidSignatureError as exc:
            raise RuntimeError("1004") from exc
        except jwt.DecodeError as exc:
            raise RuntimeError("1003") from exc
        except jwt.InvalidTokenError as exc:
            raise RuntimeError("1002") from exc
