"""Redis-based caching for market data and API responses."""

from typing import Any, Optional
import json
from datetime import datetime
from src.core.redis import get_redis_client
from src.core.logger import get_logger

logger = get_logger(__name__)


class RedisCache:
    """Redis-based cache for market data and API responses."""
    
    # Default TTL values (seconds)
    TTL_TICKER = 5  # Ticker prices are very volatile
    TTL_OHLCV = 60  # OHLCV can be cached longer
    TTL_ORDERBOOK = 2  # Order books change rapidly
    TTL_API_RESPONSE = 30  # General API response cache
    
    def __init__(self):
        """Initialize Redis cache."""
        self.redis = get_redis_client()
    
    async def get_ticker(self, symbol: str) -> Optional[dict]:
        """Get cached ticker data.
        
        Args:
            symbol: Trading symbol (e.g., 'BTC/USD')
            
        Returns:
            Cached ticker data or None
        """
        key = f"cache:ticker:{symbol.replace('/', '_')}"
        try:
            client = self.redis.get_client()
            data = await client.get(key)
            if data:
                logger.debug(f"Cache hit for ticker:{symbol}")
                return json.loads(data)
            return None
        except Exception as e:
            logger.warning(f"Redis cache get failed: {e}")
            return None
    
    async def set_ticker(self, symbol: str, data: dict, ttl: int = None) -> bool:
        """Cache ticker data.
        
        Args:
            symbol: Trading symbol
            data: Ticker data
            ttl: Time-to-live in seconds (default: TTL_TICKER)
            
        Returns:
            True if cached successfully
        """
        key = f"cache:ticker:{symbol.replace('/', '_')}"
        ttl = ttl or self.TTL_TICKER
        try:
            client = self.redis.get_client()
            await client.setex(key, ttl, json.dumps(data))
            logger.debug(f"Cached ticker:{symbol} for {ttl}s")
            return True
        except Exception as e:
            logger.warning(f"Redis cache set failed: {e}")
            return False
    
    async def get_ohlcv(self, symbol: str, timeframe: str, limit: int = 100) -> Optional[list]:
        """Get cached OHLCV data.
        
        Args:
            symbol: Trading symbol
            timeframe: Candle timeframe
            limit: Number of candles
            
        Returns:
            Cached OHLCV data or None
        """
        key = f"cache:ohlcv:{symbol.replace('/', '_')}:{timeframe}:{limit}"
        try:
            client = self.redis.get_client()
            data = await client.get(key)
            if data:
                logger.debug(f"Cache hit for ohlcv:{symbol}:{timeframe}")
                return json.loads(data)
            return None
        except Exception as e:
            logger.warning(f"Redis cache get failed: {e}")
            return None
    
    async def set_ohlcv(self, symbol: str, timeframe: str, data: list, limit: int = 100, ttl: int = None) -> bool:
        """Cache OHLCV data.
        
        Args:
            symbol: Trading symbol
            timeframe: Candle timeframe
            data: OHLCV data
            limit: Number of candles
            ttl: Time-to-live in seconds
            
        Returns:
            True if cached successfully
        """
        key = f"cache:ohlcv:{symbol.replace('/', '_')}:{timeframe}:{limit}"
        ttl = ttl or self.TTL_OHLCV
        try:
            client = self.redis.get_client()
            await client.setex(key, ttl, json.dumps(data))
            logger.debug(f"Cached ohlcv:{symbol}:{timeframe} for {ttl}s")
            return True
        except Exception as e:
            logger.warning(f"Redis cache set failed: {e}")
            return False
    
    async def get_api_response(self, cache_key: str) -> Optional[dict]:
        """Get cached API response.
        
        Args:
            cache_key: Unique cache key
            
        Returns:
            Cached response or None
        """
        key = f"cache:api:{cache_key}"
        try:
            client = self.redis.get_client()
            data = await client.get(key)
            if data:
                logger.debug(f"Cache hit for api:{cache_key}")
                return json.loads(data)
            return None
        except Exception as e:
            logger.warning(f"Redis cache get failed: {e}")
            return None
    
    async def set_api_response(self, cache_key: str, data: dict, ttl: int = None) -> bool:
        """Cache API response.
        
        Args:
            cache_key: Unique cache key
            data: Response data
            ttl: Time-to-live in seconds
            
        Returns:
            True if cached successfully
        """
        key = f"cache:api:{cache_key}"
        ttl = ttl or self.TTL_API_RESPONSE
        try:
            client = self.redis.get_client()
            await client.setex(key, ttl, json.dumps(data))
            logger.debug(f"Cached api:{cache_key} for {ttl}s")
            return True
        except Exception as e:
            logger.warning(f"Redis cache set failed: {e}")
            return False
    
    async def invalidate(self, pattern: str) -> int:
        """Invalidate cache entries matching pattern.
        
        Args:
            pattern: Redis key pattern (e.g., 'cache:ticker:*')
            
        Returns:
            Number of keys deleted
        """
        try:
            client = self.redis.get_client()
            keys = []
            async for key in client.scan_iter(match=pattern):
                keys.append(key)
            
            if keys:
                deleted = await client.delete(*keys)
                logger.info(f"Invalidated {deleted} cache entries matching {pattern}")
                return deleted
            return 0
        except Exception as e:
            logger.warning(f"Redis cache invalidation failed: {e}")
            return 0
    
    async def get_stats(self) -> dict:
        """Get cache statistics.
        
        Returns:
            Cache statistics
        """
        try:
            client = self.redis.get_client()
            info = await client.info('memory')
            
            # Count cached items by type
            ticker_count = 0
            ohlcv_count = 0
            api_count = 0
            
            async for key in client.scan_iter(match='cache:ticker:*'):
                ticker_count += 1
            async for key in client.scan_iter(match='cache:ohlcv:*'):
                ohlcv_count += 1
            async for key in client.scan_iter(match='cache:api:*'):
                api_count += 1
            
            return {
                "memory_used": info.get('used_memory_human', 'N/A'),
                "ticker_entries": ticker_count,
                "ohlcv_entries": ohlcv_count,
                "api_entries": api_count,
                "total_entries": ticker_count + ohlcv_count + api_count
            }
        except Exception as e:
            logger.warning(f"Failed to get cache stats: {e}")
            return {"error": str(e)}


# Global cache instance
_redis_cache: Optional[RedisCache] = None


def get_redis_cache() -> RedisCache:
    """Get global Redis cache instance."""
    global _redis_cache
    if _redis_cache is None:
        _redis_cache = RedisCache()
    return _redis_cache
