"""Tests for LLM response cache."""

from __future__ import annotations

import time

from agent_scout.llm.cache import LLMCache


def test_basic_put_and_get():
    cache = LLMCache()
    key = cache.make_key("model", [{"role": "user", "content": "hello"}])
    cache.put(key, {"content": "world"}, "model")
    assert cache.get(key) == {"content": "world"}


def test_cache_miss_returns_none():
    cache = LLMCache()
    assert cache.get("nonexistent") is None


def test_ttl_expiration():
    cache = LLMCache(ttl_seconds=0.01)
    key = cache.make_key("model", [{"role": "user", "content": "test"}])
    cache.put(key, {"content": "result"}, "model")
    time.sleep(0.02)
    assert cache.get(key) is None


def test_max_size_eviction():
    cache = LLMCache(max_size=2)
    key1 = cache.make_key("m", [{"role": "user", "content": "a"}])
    key2 = cache.make_key("m", [{"role": "user", "content": "b"}])
    key3 = cache.make_key("m", [{"role": "user", "content": "c"}])

    cache.put(key1, {"c": "1"}, "m")
    cache.put(key2, {"c": "2"}, "m")
    assert cache.size == 2

    cache.put(key3, {"c": "3"}, "m")
    assert cache.size == 2
    # Oldest entry (key1) should be evicted
    assert cache.get(key1) is None
    assert cache.get(key3) == {"c": "3"}


def test_invalidate():
    cache = LLMCache()
    key = cache.make_key("m", [{"role": "user", "content": "test"}])
    cache.put(key, {"c": "data"}, "m")
    assert cache.invalidate(key) is True
    assert cache.get(key) is None
    assert cache.invalidate(key) is False


def test_clear():
    cache = LLMCache()
    for i in range(5):
        key = cache.make_key("m", [{"role": "user", "content": str(i)}])
        cache.put(key, {"c": str(i)}, "m")
    assert cache.size == 5
    cache.clear()
    assert cache.size == 0


def test_disabled_cache():
    cache = LLMCache(enabled=False)
    key = cache.make_key("m", [{"role": "user", "content": "test"}])
    cache.put(key, {"c": "data"}, "m")
    assert cache.get(key) is None
    assert cache.size == 0


def test_enable_disable():
    cache = LLMCache(enabled=True)
    key = cache.make_key("m", [{"role": "user", "content": "test"}])
    cache.put(key, {"c": "data"}, "m")
    assert cache.get(key) is not None

    cache.enabled = False
    assert cache.get(key) is None


def test_hit_rate():
    cache = LLMCache()
    key = cache.make_key("m", [{"role": "user", "content": "test"}])
    cache.put(key, {"c": "data"}, "m")

    cache.get(key)  # hit
    cache.get(key)  # hit
    cache.get("missing")  # miss

    assert cache.hit_rate > 0.6


def test_stats():
    cache = LLMCache(max_size=100, ttl_seconds=60)
    stats = cache.get_stats()
    assert stats["size"] == 0
    assert stats["max_size"] == 100
    assert stats["ttl_seconds"] == 60
    assert stats["enabled"] is True


def test_deterministic_keys():
    cache = LLMCache()
    msgs = [{"role": "user", "content": "hello"}]
    key1 = cache.make_key("model", msgs, temperature=0.5)
    key2 = cache.make_key("model", msgs, temperature=0.5)
    key3 = cache.make_key("model", msgs, temperature=0.7)

    assert key1 == key2
    assert key1 != key3


def test_different_tools_produce_different_keys():
    cache = LLMCache()
    msgs = [{"role": "user", "content": "hello"}]
    key1 = cache.make_key("model", msgs, tools=[{"name": "tool_a"}])
    key2 = cache.make_key("model", msgs, tools=[{"name": "tool_b"}])
    assert key1 != key2
