"""
Caching layer for improved performance
"""

from typing import Dict, Optional, Any, List
from dataclasses import dataclass
from collections import OrderedDict
import time


@dataclass
class CacheEntry:
    value: Any
    timestamp: float
    hits: int = 0
    size: int = 1


class LRUCache:
    """LRU Cache implementation"""

    def __init__(self, ttl: int = 300, max_size: int = 1000):
        self.ttl = ttl  # seconds
        self.max_size = max_size
        self.cache: OrderedDict[str, CacheEntry] = OrderedDict()

    def get(self, key: str) -> Optional[Any]:
        """Get value from cache"""
        if key not in self.cache:
            return None

        entry = self.cache[key]

        # Check if expired
        if time.time() - entry.timestamp > self.ttl:
            del self.cache[key]
            return None

        # Move to end (most recently used)
        self.cache.move_to_end(key)
        entry.hits += 1

        return entry.value

    def set(self, key: str, value: Any, size: int = 1):
        """Set value in cache"""
        # Evict if necessary
        if len(self.cache) >= self.max_size and key not in self.cache:
            self.cache.popitem(last=False)  # Remove oldest

        entry = CacheEntry(
            value=value,
            timestamp=time.time(),
            hits=0,
            size=size,
        )

        self.cache[key] = entry
        self.cache.move_to_end(key)

    def delete(self, key: str) -> bool:
        """Delete value from cache"""
        if key in self.cache:
            del self.cache[key]
            return True
        return False

    def clear(self):
        """Clear cache"""
        self.cache.clear()

    def size(self) -> int:
        """Get cache size"""
        return len(self.cache)

    def get_stats(self) -> Dict[str, Any]:
        """Get cache statistics"""
        total_hits = sum(entry.hits for entry in self.cache.values())
        return {
            "size": len(self.cache),
            "hits": total_hits,
            "keys": list(self.cache.keys()),
        }


class ResponseCache:
    """Response cache for API calls"""

    def __init__(self, ttl: int = 300, max_size: int = 1000):
        self.cache = LRUCache(ttl=ttl, max_size=max_size)

    def generate_key(self, method: str, url: str, params: Optional[Dict] = None) -> str:
        """Generate cache key from request"""
        params_str = str(params) if params else ""
        return f"{method}:{url}:{params_str}"

    def get(self, method: str, url: str, params: Optional[Dict] = None) -> Optional[Any]:
        """Get cached response"""
        key = self.generate_key(method, url, params)
        return self.cache.get(key)

    def set(self, method: str, url: str, response: Any, params: Optional[Dict] = None):
        """Cache response"""
        key = self.generate_key(method, url, params)
        size = len(str(response))
        self.cache.set(key, response, size)

    def invalidate(self, pattern: str):
        """Invalidate cache for URL pattern"""
        stats = self.cache.get_stats()
        for key in stats["keys"]:
            if pattern in key:
                self.cache.delete(key)

    def clear(self):
        """Clear all cache"""
        self.cache.clear()
