"""Unit tests for LLMCacheStore."""
from __future__ import annotations

from unittest.mock import AsyncMock, MagicMock

import pytest

from libs.llm.cache import LLMCacheStore, build_cache_key


@pytest.mark.unit
class TestBuildCacheKey:
    def test_deterministic(self) -> None:
        key1 = build_cache_key("text", "prompt_v1", "v1", "llama3.2", "1.0.0")
        key2 = build_cache_key("text", "prompt_v1", "v1", "llama3.2", "1.0.0")
        assert key1 == key2

    def test_different_inputs_different_keys(self) -> None:
        key1 = build_cache_key("text_a", "p", "v1", "llama3.2")
        key2 = build_cache_key("text_b", "p", "v1", "llama3.2")
        assert key1 != key2


@pytest.mark.unit
class TestLLMCacheStore:
    @pytest.mark.asyncio
    async def test_get_returns_none_on_miss(self) -> None:
        """Cache miss returns None."""
        cache = LLMCacheStore()
        mock_session = AsyncMock()
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = None
        mock_session.execute = AsyncMock(return_value=mock_result)

        result = await cache.get(mock_session, "deadbeef" * 8)
        assert result is None

    @pytest.mark.asyncio
    async def test_put_stores_entry(self) -> None:
        """Cache put creates a new row when key is absent."""
        cache = LLMCacheStore()
        mock_session = AsyncMock()

        # Simulate no existing entry
        mock_result = MagicMock()
        mock_result.scalar_one_or_none.return_value = None
        mock_session.execute = AsyncMock(return_value=mock_result)
        mock_session.add = MagicMock()
        mock_session.flush = AsyncMock()

        await cache.put(
            session=mock_session,
            cache_key="deadbeef" * 8,
            document_id="DOC::test",
            model_name="llama3.2",
            prompt_version="v1",
            schema_version="1.0.0",
            raw_prompt='[{"role":"user","content":"test"}]',
            raw_response='{"event_type":"unknown"}',
            normalized={"event_type": "unknown"},
            token_usage={"prompt_tokens": 10, "completion_tokens": 5},
            elapsed_ms=250,
        )

        mock_session.add.assert_called_once()
        mock_session.flush.assert_called_once()
