import os
import sys
from unittest.mock import MagicMock, patch, AsyncMock

import pytest

sys.path.insert(
    0, os.path.abspath("../../..")
)  # Adds the parent directory to the system path


# Tests for RedisSemanticCache
def test_redis_semantic_cache_initialization(monkeypatch):
    # Mock the redisvl import
    semantic_cache_mock = MagicMock()
    with patch.dict("sys.modules", {
        "redisvl.extensions.llmcache": MagicMock(SemanticCache=semantic_cache_mock),
        "redisvl.utils.vectorize": MagicMock(CustomTextVectorizer=MagicMock())
    }):
        from litellm.caching.redis_semantic_cache import RedisSemanticCache
        
        # Set environment variables
        monkeypatch.setenv("REDIS_HOST", "localhost")
        monkeypatch.setenv("REDIS_PORT", "6379")
        monkeypatch.setenv("REDIS_PASSWORD", "test_password")
        
        # Initialize the cache with a similarity threshold
        redis_semantic_cache = RedisSemanticCache(similarity_threshold=0.8)
        
        # Verify the semantic cache was initialized with correct parameters
        assert redis_semantic_cache.similarity_threshold == 0.8
        
        # Use pytest.approx for floating point comparison to handle precision issues
        assert redis_semantic_cache.distance_threshold == pytest.approx(0.2, abs=1e-10)
        assert redis_semantic_cache.embedding_model == "text-embedding-ada-002"
        
        # Test initialization with missing similarity_threshold
        with pytest.raises(ValueError, match="similarity_threshold must be provided"):
            RedisSemanticCache()


def test_redis_semantic_cache_get_cache(monkeypatch):
    # Mock the redisvl import and embedding function
    semantic_cache_mock = MagicMock()
    custom_vectorizer_mock = MagicMock()
    
    with patch.dict("sys.modules", {
        "redisvl.extensions.llmcache": MagicMock(SemanticCache=semantic_cache_mock),
        "redisvl.utils.vectorize": MagicMock(CustomTextVectorizer=custom_vectorizer_mock)
    }):
        from litellm.caching.redis_semantic_cache import RedisSemanticCache
        
        # Set environment variables
        monkeypatch.setenv("REDIS_HOST", "localhost")
        monkeypatch.setenv("REDIS_PORT", "6379")
        monkeypatch.setenv("REDIS_PASSWORD", "test_password")
        
        # Initialize cache
        redis_semantic_cache = RedisSemanticCache(similarity_threshold=0.8)
        
        # Mock the llmcache.check method to return a result
        mock_result = [
            {
                "prompt": "What is the capital of France?",
                "response": '{"content": "Paris is the capital of France."}',
                "vector_distance": 0.1  # Distance of 0.1 means similarity of 0.9
            }
        ]
        redis_semantic_cache.llmcache.check = MagicMock(return_value=mock_result)
        
        # Mock the embedding function
        with patch("litellm.embedding", return_value={"data": [{"embedding": [0.1, 0.2, 0.3]}]}):
            # Test get_cache with a message
            result = redis_semantic_cache.get_cache(
                key="test_key",
                messages=[{"content": "What is the capital of France?"}]
            )
            
            # Verify result is properly parsed
            assert result == {"content": "Paris is the capital of France."}
            
            # Verify llmcache.check was called
            redis_semantic_cache.llmcache.check.assert_called_once()


@pytest.mark.asyncio
async def test_redis_semantic_cache_async_get_cache(monkeypatch):
    # Mock the redisvl import
    semantic_cache_mock = MagicMock()
    custom_vectorizer_mock = MagicMock()
    
    with patch.dict("sys.modules", {
        "redisvl.extensions.llmcache": MagicMock(SemanticCache=semantic_cache_mock),
        "redisvl.utils.vectorize": MagicMock(CustomTextVectorizer=custom_vectorizer_mock)
    }):
        from litellm.caching.redis_semantic_cache import RedisSemanticCache
        
        # Set environment variables
        monkeypatch.setenv("REDIS_HOST", "localhost")
        monkeypatch.setenv("REDIS_PORT", "6379")
        monkeypatch.setenv("REDIS_PASSWORD", "test_password")
        
        # Initialize cache
        redis_semantic_cache = RedisSemanticCache(similarity_threshold=0.8)
        
        # Mock the async methods
        mock_result = [
            {
                "prompt": "What is the capital of France?",
                "response": '{"content": "Paris is the capital of France."}',
                "vector_distance": 0.1  # Distance of 0.1 means similarity of 0.9
            }
        ]
        
        redis_semantic_cache.llmcache.acheck = AsyncMock(return_value=mock_result)
        redis_semantic_cache._get_async_embedding = AsyncMock(return_value=[0.1, 0.2, 0.3])
        
        # Test async_get_cache with a message
        result = await redis_semantic_cache.async_get_cache(
            key="test_key",
            messages=[{"content": "What is the capital of France?"}],
            metadata={}
        )
        
        # Verify result is properly parsed
        assert result == {"content": "Paris is the capital of France."}
        
        # Verify methods were called
        redis_semantic_cache._get_async_embedding.assert_called_once()
        redis_semantic_cache.llmcache.acheck.assert_called_once() 