"""
Caching utilities for improved performance.
"""
from functools import wraps
from typing import Callable, Any, Optional
import time
import hashlib
import json


class SimpleCache:
    """Simple in-memory cache with TTL support."""
    
    def __init__(self):
        self._cache = {}
        self._expiry = {}
    
    def get(self, key: str) -> Optional[Any]:
        """Get value from cache if not expired."""
        if key not in self._cache:
            return None
        
        # Check expiry
        if key in self._expiry and time.time() > self._expiry[key]:
            del self._cache[key]
            del self._expiry[key]
            return None
        
        return self._cache[key]
    
    def set(self, key: str, value: Any, ttl: Optional[int] = None):
        """Set value in cache with optional TTL (seconds)."""
        self._cache[key] = value
        
        if ttl:
            self._expiry[key] = time.time() + ttl
    
    def delete(self, key: str):
        """Delete value from cache."""
        if key in self._cache:
            del self._cache[key]
        if key in self._expiry:
            del self._expiry[key]
    
    def clear(self):
        """Clear all cache."""
        self._cache.clear()
        self._expiry.clear()
    
    def size(self) -> int:
        """Get number of cached items."""
        return len(self._cache)


# Global cache instance
_cache = SimpleCache()


def cached(ttl: int = 300, key_prefix: str = ""):
    """Decorator for caching function results.
    
    Args:
        ttl: Time to live in seconds (default: 5 minutes)
        key_prefix: Prefix for cache key
        
    Usage:
        @cached(ttl=60)
        def expensive_function(arg1, arg2):
            return result
    """
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Generate cache key from function name and arguments
            key_data = {
                "func": f"{func.__module__}.{func.__name__}",
                "args": str(args),
                "kwargs": str(sorted(kwargs.items()))
            }
            key_str = json.dumps(key_data, sort_keys=True)
            cache_key = f"{key_prefix}:{hashlib.md5(key_str.encode()).hexdigest()}"
            
            # Try to get from cache
            result = _cache.get(cache_key)
            if result is not None:
                return result
            
            # Execute function
            result = func(*args, **kwargs)
            
            # Store in cache
            _cache.set(cache_key, result, ttl=ttl)
            
            return result
        
        return wrapper
    return decorator


def get_cache() -> SimpleCache:
    """Get global cache instance."""
    return _cache


# Cache statistics
def cache_stats() -> dict:
    """Get cache statistics."""
    return {
        "size": _cache.size(),
        "items": list(_cache._cache.keys())[:10]  # First 10 keys
    }
