"""Coverage gap tests for enterprise/auth.py — lines 91, 203-204, 212-213, 393."""

from __future__ import annotations

import time

from orxaq.enterprise.auth import (
    APIKeyStore,
    AuthMiddleware,
    RateLimiter,
    TokenProvider,
)


class TestAPIKeyStoreGaps:
    """Cover line 91 (record is None after hash lookup race) and line 94 (expired key)."""

    def test_expired_key_returns_none(self) -> None:
        """Line 94-95: expires_at > 0 and time.time() > expires_at."""
        store = APIKeyStore()
        raw, key = store.generate_key(name="expiring", ttl_seconds=0.001)
        time.sleep(0.05)
        result = store.validate(raw)
        assert result is None

    def test_valid_key_not_expired(self) -> None:
        """Lines 93-97 happy path: non-expired key returns the record."""
        store = APIKeyStore()
        raw, key = store.generate_key(name="fresh", ttl_seconds=3600)
        result = store.validate(raw)
        assert result is not None
        assert result.name == "fresh"

    def test_never_expiring_key_valid(self) -> None:
        """Line 94: expires_at == 0 means never expires — skip check."""
        store = APIKeyStore()
        raw, key = store.generate_key(name="forever")
        result = store.validate(raw)
        assert result is not None


class TestTokenProviderGaps:
    """Cover lines 203-204 (invalid base64 in sig), 212-213 (malformed JSON payload)."""

    def test_invalid_base64_signature_returns_none(self) -> None:
        """Lines 203-204: _b64url_decode raises on invalid base64."""
        tp = TokenProvider()
        # Craft a token where the signature part is not valid base64url
        valid_token = tp.issue("user", scopes=frozenset())
        parts = valid_token.split(".")
        bad_token = parts[0] + "." + parts[1] + ".!not-base64!"
        result = tp.validate(bad_token)
        assert result is None

    def test_malformed_json_payload_returns_none(self) -> None:
        """Lines 212-213: json.loads raises ValueError on bad JSON."""
        import base64

        tp = TokenProvider()

        # Build a token with valid base64url payload that decodes to non-JSON
        def b64url_encode(data: bytes) -> str:
            return base64.urlsafe_b64encode(data).rstrip(b"=").decode()

        import hashlib
        import hmac as _hmac

        header = b64url_encode(b'{"alg":"HS256"}')
        bad_payload = b64url_encode(b"NOT JSON {{{{")
        signing_input = f"{header}.{bad_payload}"
        secret = tp._secret  # access internal secret
        sig = b64url_encode(_hmac.new(secret, signing_input.encode(), hashlib.sha256).digest())
        bad_token = f"{header}.{bad_payload}.{sig}"
        result = tp.validate(bad_token)
        assert result is None

    def test_wrong_format_token_returns_none(self) -> None:
        """Token without exactly 3 parts returns None."""
        tp = TokenProvider()
        result = tp.validate("only.two")
        assert result is None


class TestAuthMiddlewareBearerRateLimit:
    """Cover line 393: rate limiter triggered for bearer token path."""

    def test_bearer_token_rate_limited(self) -> None:
        """Line 392-398: rate_limiter.allow() returns False for bearer."""
        tp = TokenProvider()
        # Capacity=1 refill_rate=0.0 — second call exceeds limit
        rl = RateLimiter(capacity=1, refill_rate=0.0)
        mw = AuthMiddleware(token_provider=tp, rate_limiter=rl)

        token = tp.issue("alice", scopes=frozenset({"read"}))
        headers = {"Authorization": f"Bearer {token}"}

        r1 = mw.authenticate(headers, "/api/v1/data")
        assert r1.authenticated
        assert not r1.rate_limited

        r2 = mw.authenticate(headers, "/api/v1/data")
        assert r2.authenticated
        assert r2.rate_limited
