"""Tests for the auth manager."""

from __future__ import annotations

from datetime import timedelta

import pytest

from a2a_mesh.auth import AuthManager
from a2a_mesh.exceptions import (
    AuthError,
    InsufficientScopeError,
    TokenExpiredError,
)


class TestAuthManager:
    """Tests for AuthManager."""

    def test_issue_token(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="agent-a",
            subject="agent-b",
            scopes=["read", "write"],
        )
        assert token.issuer == "agent-a"
        assert token.subject == "agent-b"
        assert "read" in token.scopes
        assert token.token  # non-empty JWT string

    def test_validate_valid_token(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="a", subject="b", scopes=["read"]
        )
        claims = auth_manager.validate_token(token.token)
        assert claims["iss"] == "a"
        assert claims["sub"] == "b"
        assert "read" in claims["scopes"]

    def test_validate_with_required_scopes(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="a", subject="b", scopes=["read", "write"]
        )
        claims = auth_manager.validate_token(
            token.token, required_scopes=["read"]
        )
        assert claims["sub"] == "b"

    def test_validate_insufficient_scopes(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="a", subject="b", scopes=["read"]
        )
        with pytest.raises(InsufficientScopeError):
            auth_manager.validate_token(
                token.token, required_scopes=["admin"]
            )

    def test_validate_expired_token(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="a",
            subject="b",
            scopes=["read"],
            ttl=timedelta(seconds=-1),  # already expired
        )
        with pytest.raises(TokenExpiredError):
            auth_manager.validate_token(token.token)

    def test_validate_invalid_token(self, auth_manager: AuthManager) -> None:
        with pytest.raises(AuthError):
            auth_manager.validate_token("not.a.valid.jwt")

    def test_revoke_token(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="a", subject="b", scopes=["read"]
        )
        auth_manager.revoke_token(token.token)
        with pytest.raises(AuthError, match="revoked"):
            auth_manager.validate_token(token.token)

    def test_revoke_invalid_token(self, auth_manager: AuthManager) -> None:
        with pytest.raises(AuthError):
            auth_manager.revoke_token("garbage")

    def test_audit_log(self, auth_manager: AuthManager) -> None:
        auth_manager.issue_token(
            issuer="a", subject="b", scopes=["read"]
        )
        log = auth_manager.get_audit_log()
        assert len(log) >= 1
        assert log[0].action == "token_issued"
        assert log[0].issuer == "a"

    def test_audit_log_limit(self, auth_manager: AuthManager) -> None:
        for i in range(10):
            auth_manager.issue_token(
                issuer=f"a{i}", subject="b", scopes=["read"]
            )
        log = auth_manager.get_audit_log(limit=5)
        assert len(log) == 5

    def test_auto_generated_secret(self) -> None:
        mgr = AuthManager()
        assert len(mgr.secret) > 10
        # Should still work
        token = mgr.issue_token(issuer="a", subject="b", scopes=[])
        mgr.validate_token(token.token)

    def test_multiple_scopes_validation(self, auth_manager: AuthManager) -> None:
        token = auth_manager.issue_token(
            issuer="a",
            subject="b",
            scopes=["read", "write", "delete"],
        )
        claims = auth_manager.validate_token(
            token.token, required_scopes=["read", "write"]
        )
        assert "delete" in claims["scopes"]
