"""Tests for metrics pricing_cache module."""

import time


from local_deep_research.metrics.pricing.pricing_cache import PricingCache


class TestPricingCacheInit:
    """Tests for PricingCache initialization."""

    def test_initializes_with_default_ttl(self):
        """Should initialize with default TTL of 3600 seconds."""
        cache = PricingCache()
        assert cache.cache_ttl == 3600

    def test_initializes_with_custom_ttl(self):
        """Should initialize with custom TTL."""
        cache = PricingCache(cache_ttl=7200)
        assert cache.cache_ttl == 7200

    def test_initializes_empty_cache(self):
        """Should initialize with empty in-memory cache."""
        cache = PricingCache()
        assert len(cache._cache) == 0

    def test_cache_dir_is_deprecated(self):
        """Cache dir parameter should be ignored (deprecated)."""
        cache = PricingCache(cache_dir="/some/path")
        # Should not raise and should work normally
        assert len(cache._cache) == 0


class TestPricingCacheGetSet:
    """Tests for PricingCache get/set methods."""

    def test_get_returns_none_for_missing_key(self):
        """Should return None for non-existent key."""
        cache = PricingCache()
        result = cache.get("nonexistent")
        assert result is None

    def test_set_stores_data(self):
        """Should store data in cache."""
        cache = PricingCache()
        cache.set("test_key", {"value": 123})

        assert "test_key" in cache._cache
        assert cache._cache["test_key"] == {"value": 123}

    def test_get_returns_valid_data(self):
        """Should return data for valid key."""
        cache = PricingCache()
        cache.set("test_key", {"value": 456})

        result = cache.get("test_key")
        assert result == {"value": 456}

    def test_get_returns_none_for_expired_key(self):
        """Should return None and remove expired entries."""
        # audit: PUNCHLIST reviewed 2026-05 — KEEP (TIMING_SLEEP).
        cache = PricingCache(cache_ttl=1)  # 1 second TTL
        cache.set("test_key", {"value": 789})

        # Wait for expiration
        time.sleep(1.1)  # allow: unmarked-sleep

        result = cache.get("test_key")
        assert result is None
        assert "test_key" not in cache._cache


class TestPricingCacheModelPricing:
    """Tests for model pricing methods."""

    def test_get_model_pricing_returns_none_for_missing(self):
        """Should return None for missing model pricing."""
        cache = PricingCache()
        result = cache.get_model_pricing("gpt-4")
        assert result is None

    def test_set_model_pricing_stores_with_prefix(self):
        """Should store pricing with 'model:' prefix."""
        cache = PricingCache()
        pricing = {"prompt": 0.03, "completion": 0.06}
        cache.set_model_pricing("gpt-4", pricing)

        assert "model:gpt-4" in cache._cache
        assert cache._cache["model:gpt-4"] == pricing

    def test_get_model_pricing_retrieves_stored(self):
        """Should retrieve stored model pricing."""
        cache = PricingCache()
        pricing = {"prompt": 0.03, "completion": 0.06}
        cache.set_model_pricing("gpt-4", pricing)

        result = cache.get_model_pricing("gpt-4")
        assert result == pricing


class TestPricingCacheAllPricing:
    """Tests for all pricing methods."""

    def test_get_all_pricing_returns_none_when_not_set(self):
        """Should return None when all pricing not cached."""
        cache = PricingCache()
        result = cache.get_all_pricing()
        assert result is None

    def test_set_all_pricing_stores_data(self):
        """Should store all pricing data."""
        cache = PricingCache()
        all_pricing = {
            "gpt-4": {"prompt": 0.03, "completion": 0.06},
            "gpt-3.5-turbo": {"prompt": 0.001, "completion": 0.002},
        }
        cache.set_all_pricing(all_pricing)

        assert "all_models" in cache._cache
        assert cache._cache["all_models"] == all_pricing

    def test_get_all_pricing_retrieves_stored(self):
        """Should retrieve stored all pricing."""
        cache = PricingCache()
        all_pricing = {
            "gpt-4": {"prompt": 0.03, "completion": 0.06},
        }
        cache.set_all_pricing(all_pricing)

        result = cache.get_all_pricing()
        assert result == all_pricing


class TestPricingCacheClear:
    """Tests for cache clearing methods."""

    def test_clear_removes_all_entries(self):
        """Should remove all cache entries."""
        cache = PricingCache()
        cache.set("key1", "value1")
        cache.set("key2", "value2")

        cache.clear()

        assert len(cache._cache) == 0

    def test_clear_expired_removes_only_expired(self):
        """Should remove only expired entries."""
        # audit: PUNCHLIST reviewed 2026-05 — KEEP (TIMING_SLEEP).
        cache = PricingCache(cache_ttl=2)  # 2 second TTL
        cache.set("old_key", "old_value")

        # Wait for old entry to expire
        time.sleep(2.1)  # allow: unmarked-sleep

        # Add new entry
        cache.set("new_key", "new_value")

        cache.clear_expired()

        assert "old_key" not in cache._cache
        assert "new_key" in cache._cache

    def test_clear_expired_handles_empty_cache(self):
        """Should handle empty cache without error."""
        cache = PricingCache()
        cache.clear_expired()  # Should not raise
        assert len(cache._cache) == 0


class TestPricingCacheStats:
    """Tests for cache statistics."""

    def test_get_cache_stats_returns_correct_structure(self):
        """Should return stats with correct keys."""
        cache = PricingCache(cache_ttl=3600)
        stats = cache.get_cache_stats()

        assert "total_entries" in stats
        assert "max_entries" in stats
        assert "cache_type" in stats
        assert "cache_ttl" in stats

    def test_get_cache_stats_counts_entries(self):
        """Should count total entries correctly."""
        cache = PricingCache()
        cache.set("key1", "value1")
        cache.set("key2", "value2")
        cache.set("key3", "value3")

        stats = cache.get_cache_stats()

        assert stats["total_entries"] == 3

    def test_get_cache_stats_expired_entries_evicted(self):
        """TTLCache automatically evicts expired entries on get_cache_stats."""
        # audit: PUNCHLIST reviewed 2026-05 — KEEP (TIMING_SLEEP).
        cache = PricingCache(cache_ttl=1)
        cache.set("key1", "value1")

        time.sleep(1.1)  # allow: unmarked-sleep

        stats = cache.get_cache_stats()

        # TTLCache evicts expired entries automatically when expire() is called
        assert stats["total_entries"] == 0

    def test_get_cache_stats_shows_cache_type(self):
        """Should show TTLCache cache type."""
        cache = PricingCache()
        stats = cache.get_cache_stats()

        assert stats["cache_type"] == "TTLCache"

    def test_get_cache_stats_shows_ttl(self):
        """Should show configured TTL."""
        cache = PricingCache(cache_ttl=7200)
        stats = cache.get_cache_stats()

        assert stats["cache_ttl"] == 7200


class TestPricingCacheTTL:
    """Tests for TTLCache behavior."""

    def test_cache_respects_ttl(self):
        """Should respect TTL for entries."""
        # audit: PUNCHLIST reviewed 2026-05 — KEEP (TIMING_SLEEP).
        cache = PricingCache(cache_ttl=1)
        cache.set("key1", "value1")

        # Entry should be available immediately
        assert cache.get("key1") == "value1"

        # Wait for expiration
        time.sleep(1.1)  # allow: unmarked-sleep

        # Entry should be expired
        assert cache.get("key1") is None

    def test_cache_respects_maxsize(self):
        """Should respect maxsize by evicting old entries."""
        # Create cache with small maxsize
        cache = PricingCache()
        # TTLCache with maxsize=500 is default
        assert cache._cache.maxsize == 500
