"""Tests for JWT identity extraction."""

from __future__ import annotations

import base64
import json

from attestmcp.identity import IdentityExtractor
from attestmcp.models import IdentitySource, TrustLevel


def _make_unsigned_jwt(claims: dict[str, object]) -> str:
    """Create an unsigned JWT (alg: none) for testing claimed extraction.

    This is NOT a valid JWT for production use. It's only for testing
    the claim extraction logic without needing real signing keys.
    """
    header = base64.urlsafe_b64encode(
        json.dumps({"alg": "none", "typ": "JWT"}).encode()
    ).rstrip(b"=")
    payload = base64.urlsafe_b64encode(
        json.dumps(claims).encode()
    ).rstrip(b"=")
    return f"{header.decode()}.{payload.decode()}."


class TestIdentityExtractorAnonymous:
    """Anonymous identity when no credentials are present."""

    def test_no_authorization_header(self) -> None:
        extractor = IdentityExtractor()
        identity = extractor.extract(None)
        assert identity.source == IdentitySource.ANONYMOUS
        assert identity.trust_level == TrustLevel.ANONYMOUS
        assert identity.verified is False

    def test_empty_authorization_header(self) -> None:
        extractor = IdentityExtractor()
        identity = extractor.extract("")
        assert identity.source == IdentitySource.ANONYMOUS

    def test_invalid_authorization_format(self) -> None:
        extractor = IdentityExtractor()
        identity = extractor.extract("NotBearer xyz")
        assert identity.source == IdentitySource.ANONYMOUS

    def test_session_id_preserved_on_anonymous(self) -> None:
        extractor = IdentityExtractor()
        identity = extractor.extract(None, session_id="sess-abc")
        assert identity.session_id == "sess-abc"


class TestIdentityExtractorClaimed:
    """Claimed identity — JWT decoded but not signature-verified."""

    def test_extracts_email_as_user(self) -> None:
        token = _make_unsigned_jwt({"email": "alice@example.com"})
        extractor = IdentityExtractor()  # No JWKS = claimed mode
        identity = extractor.extract(f"Bearer {token}")
        assert identity.source == IdentitySource.OAUTH_JWT
        assert identity.user == "alice@example.com"
        assert identity.trust_level == TrustLevel.CLAIMED
        assert identity.verified is False

    def test_extracts_sub_as_user_fallback(self) -> None:
        token = _make_unsigned_jwt({"sub": "user-123"})
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.user == "user-123"

    def test_extracts_azp_as_agent_name(self) -> None:
        token = _make_unsigned_jwt({
            "email": "bot@example.com",
            "azp": "support-agent-v2",
        })
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.agent_name == "support-agent-v2"

    def test_extracts_client_id_as_agent_name_fallback(self) -> None:
        token = _make_unsigned_jwt({"client_id": "my-agent"})
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.agent_name == "my-agent"

    def test_extracts_org(self) -> None:
        token = _make_unsigned_jwt({
            "email": "alice@acme.com",
            "org": "acme-corp",
        })
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.org == "acme-corp"

    def test_extracts_organization_fallback(self) -> None:
        token = _make_unsigned_jwt({"organization": "beta-inc"})
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.org == "beta-inc"

    def test_extracts_role_string(self) -> None:
        token = _make_unsigned_jwt({"role": "admin"})
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.role == "admin"

    def test_extracts_roles_list_takes_first(self) -> None:
        token = _make_unsigned_jwt({"roles": ["editor", "viewer"]})
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}")
        assert identity.role == "editor"

    def test_full_claim_extraction(self) -> None:
        token = _make_unsigned_jwt({
            "email": "deploy-bot@acme.com",
            "azp": "support-agent-v2",
            "org": "acme-corp",
            "role": "support-read-only",
        })
        extractor = IdentityExtractor()
        identity = extractor.extract(f"Bearer {token}", session_id="sess-xyz")

        assert identity.source == IdentitySource.OAUTH_JWT
        assert identity.user == "deploy-bot@acme.com"
        assert identity.agent_name == "support-agent-v2"
        assert identity.org == "acme-corp"
        assert identity.role == "support-read-only"
        assert identity.session_id == "sess-xyz"
        assert identity.verified is False
        assert identity.trust_level == TrustLevel.CLAIMED

    def test_malformed_token_returns_anonymous(self) -> None:
        extractor = IdentityExtractor()
        identity = extractor.extract("Bearer not-a-real-jwt")
        assert identity.source == IdentitySource.ANONYMOUS

    def test_case_insensitive_bearer(self) -> None:
        token = _make_unsigned_jwt({"email": "test@test.com"})
        extractor = IdentityExtractor()
        identity = extractor.extract(f"bearer {token}")
        assert identity.user == "test@test.com"
