"""
Unit tests for API key validation and caching.

Tests in-memory cache, background refresh, and validation logic.
"""

import pytest
import asyncio
import time
from unittest.mock import patch, MagicMock, AsyncMock


class TestApiKeyCache:
    """Test API key cache."""
    
    def test_create_cache(self):
        """Create an API key cache."""
        from veena3modal.api.auth import ApiKeyCache
        
        cache = ApiKeyCache()
        assert cache is not None
    
    def test_cache_miss_returns_none(self):
        """Cache miss should return None."""
        from veena3modal.api.auth import ApiKeyCache
        
        cache = ApiKeyCache()
        result = cache.get("nonexistent_key")
        
        assert result is None
    
    def test_cache_stores_and_retrieves(self):
        """Cache should store and retrieve key data."""
        from veena3modal.api.auth import ApiKeyCache
        
        cache = ApiKeyCache()
        
        key_data = {
            "user_id": "user-123",
            "rate_limit": 100,
            "credits": 1000.0,
            "is_active": True,
        }
        
        cache.set("api_key_hash", key_data)
        result = cache.get("api_key_hash")
        
        assert result == key_data
    
    def test_cache_expiry(self):
        """Cache entries should expire after TTL."""
        from veena3modal.api.auth import ApiKeyCache
        
        cache = ApiKeyCache(ttl_seconds=1)
        cache.set("key1", {"user_id": "user-1"})
        
        # Should be present immediately
        assert cache.get("key1") is not None
        
        # Wait for expiry
        time.sleep(1.1)
        
        # Should be expired
        assert cache.get("key1") is None


class TestApiKeyValidation:
    """Test API key validation logic."""
    
    def test_validate_valid_key(self):
        """Valid key should pass validation."""
        from veena3modal.api.auth import ApiKeyValidator, ApiKeyCache
        
        cache = ApiKeyCache()
        cache.set("valid_hash", {
            "user_id": "user-123",
            "is_active": True,
            "credits": 100.0,
        })
        
        validator = ApiKeyValidator(cache=cache)
        result = validator.validate("valid_hash")
        
        assert result.is_valid is True
        assert result.user_id == "user-123"
    
    def test_validate_inactive_key(self):
        """Inactive key should fail validation."""
        from veena3modal.api.auth import ApiKeyValidator, ApiKeyCache
        
        cache = ApiKeyCache()
        cache.set("inactive_hash", {
            "user_id": "user-123",
            "is_active": False,
            "credits": 100.0,
        })
        
        validator = ApiKeyValidator(cache=cache)
        result = validator.validate("inactive_hash")
        
        assert result.is_valid is False
        assert result.error_code == "INVALID_API_KEY"
    
    def test_validate_insufficient_credits(self):
        """Key with insufficient credits should fail."""
        from veena3modal.api.auth import ApiKeyValidator, ApiKeyCache
        
        cache = ApiKeyCache()
        cache.set("no_credits_hash", {
            "user_id": "user-123",
            "is_active": True,
            "credits": 0.0,
        })
        
        validator = ApiKeyValidator(cache=cache)
        result = validator.validate("no_credits_hash")
        
        assert result.is_valid is False
        assert result.error_code == "INSUFFICIENT_CREDITS"
    
    def test_validate_unknown_key(self):
        """Unknown key should fail validation."""
        from veena3modal.api.auth import ApiKeyValidator, ApiKeyCache
        
        cache = ApiKeyCache()
        validator = ApiKeyValidator(cache=cache)
        
        result = validator.validate("unknown_hash")
        
        assert result.is_valid is False
        assert result.error_code == "INVALID_API_KEY"


class TestApiKeyHashing:
    """Test API key hashing utilities."""
    
    def test_hash_api_key(self):
        """API key should be hashed consistently."""
        from veena3modal.api.auth import hash_api_key
        
        key = "vn3_test_key_12345"
        hash1 = hash_api_key(key)
        hash2 = hash_api_key(key)
        
        assert hash1 == hash2
        assert hash1 != key  # Should not be plaintext
    
    def test_different_keys_different_hashes(self):
        """Different keys should produce different hashes."""
        from veena3modal.api.auth import hash_api_key
        
        hash1 = hash_api_key("key_one")
        hash2 = hash_api_key("key_two")
        
        assert hash1 != hash2


class TestGracefulDegradation:
    """Test authentication graceful degradation."""
    
    def test_bypass_mode_allows_all(self):
        """Bypass mode should allow all requests."""
        from veena3modal.api.auth import ApiKeyValidator, ApiKeyCache
        
        cache = ApiKeyCache()
        validator = ApiKeyValidator(cache=cache, bypass_mode=True)
        
        result = validator.validate("any_key_at_all")
        
        assert result.is_valid is True
        assert result.user_id == "bypass_user"
    
    def test_validator_without_cache(self):
        """Validator should work without external cache (in-memory)."""
        from veena3modal.api.auth import get_api_validator
        
        validator = get_api_validator()
        assert validator is not None


class TestExtractApiKey:
    """Test API key extraction from headers."""
    
    def test_extract_from_bearer_token(self):
        """Extract API key from Bearer token."""
        from veena3modal.api.auth import extract_api_key
        
        headers = {"authorization": "Bearer vn3_test_key_123"}
        key = extract_api_key(headers)
        
        assert key == "vn3_test_key_123"
    
    def test_extract_from_x_api_key(self):
        """Extract API key from X-API-Key header."""
        from veena3modal.api.auth import extract_api_key
        
        headers = {"x-api-key": "vn3_test_key_456"}
        key = extract_api_key(headers)
        
        assert key == "vn3_test_key_456"
    
    def test_extract_missing_key(self):
        """Missing key should return None."""
        from veena3modal.api.auth import extract_api_key
        
        headers = {"content-type": "application/json"}
        key = extract_api_key(headers)
        
        assert key is None
    
    def test_bearer_preferred_over_x_api_key(self):
        """Bearer token should be preferred if both present."""
        from veena3modal.api.auth import extract_api_key
        
        headers = {
            "authorization": "Bearer vn3_bearer_key",
            "x-api-key": "vn3_header_key",
        }
        key = extract_api_key(headers)
        
        assert key == "vn3_bearer_key"

