"""JWT 工具签发/校验。"""

from __future__ import annotations

import pytest

from linksoul_agentsdk.jwt_util import JwtUtil


_SECRET = "0123456789abcdef0123456789abcdef"  # 32 bytes


def test_generate_token_includes_claims_and_exp():
    token = JwtUtil.generate_token(_SECRET, {"appId": "x", "callbackTypes": "[]"})
    decoded = JwtUtil.validate_token(_SECRET, token)
    assert decoded["appId"] == "x"
    assert decoded["callbackTypes"] == "[]"
    assert "exp" in decoded


def test_short_secret_rejected():
    with pytest.raises(ValueError):
        JwtUtil.generate_token("short", {"a": 1})


def test_empty_token_returns_1005():
    with pytest.raises(RuntimeError) as exc_info:
        JwtUtil.validate_token(_SECRET, "")
    assert str(exc_info.value) == "1005"


def test_bad_signature_returns_1004():
    token = JwtUtil.generate_token(_SECRET, {"appId": "x"})
    wrong_secret = "wrongwrongwrongwrongwrongwrongwr"  # 32 bytes
    with pytest.raises(RuntimeError) as exc_info:
        JwtUtil.validate_token(wrong_secret, token)
    assert str(exc_info.value) == "1004"


def test_malformed_token_returns_1003():
    with pytest.raises(RuntimeError) as exc_info:
        JwtUtil.validate_token(_SECRET, "not-a-jwt")
    # 1002 (Unsupported) 与 1003 (Decode) 取决于 PyJWT 内部判定，二者皆可接受
    assert str(exc_info.value) in {"1002", "1003"}


def test_expired_token_returns_1001(monkeypatch):
    import time as _time

    # 把过期时间设为 -1 秒（已经过期）
    monkeypatch.setattr(
        "linksoul_agentsdk.jwt_util._EXPIRATION_SECONDS", -1, raising=False
    )
    monkeypatch.setattr(JwtUtil, "EXPIRATION_SECONDS", -1, raising=False)

    # 由于上面 monkeypatch 改的是模块级常量，generate_token 内部仍读取闭包 — 直接手工签发过期 token
    import jwt

    token = jwt.encode(
        {"appId": "x", "exp": int(_time.time()) - 60},
        _SECRET,
        algorithm="HS256",
    )
    if isinstance(token, bytes):
        token = token.decode()
    with pytest.raises(RuntimeError) as exc_info:
        JwtUtil.validate_token(_SECRET, token)
    assert str(exc_info.value) == "1001"
