"""
Cache utilities.
Local-first behavior: use in-memory cache by default.
Redis is only used when explicitly enabled via environment variables.
"""
import time
import threading
from typing import Optional, Any
import json

from app.utils.logger import get_logger
from app.config import CacheConfig

logger = get_logger(__name__)


class MemoryCache:
    """内存缓存（Redis 不可用时的备选方案）"""
    
    def __init__(self):
        self._cache = {}
        self._lock = threading.Lock()
    
    def get(self, key: str) -> Optional[str]:
        with self._lock:
            if key in self._cache:
                data, expiry = self._cache[key]
                if expiry > time.time():
                    return data
                else:
                    del self._cache[key]
            return None
    
    def setex(self, key: str, ttl: int, value: str):
        with self._lock:
            expiry = time.time() + ttl
            self._cache[key] = (value, expiry)
    
    def delete(self, key: str):
        with self._lock:
            if key in self._cache:
                del self._cache[key]
    
    def clear(self):
        with self._lock:
            self._cache.clear()


class CacheManager:
    """缓存管理器"""
    
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialized = False
        return cls._instance
    
    def __init__(self):
        if self._initialized:
            return
            
        self._initialized = True
        self._client = None
        self._use_redis = False

        # Local-first: do NOT touch Redis unless explicitly enabled.
        if not CacheConfig.ENABLED:
            self._client = MemoryCache()
            self._use_redis = False
            return

        # Try Redis only when enabled.
        try:
            import redis
            from app.config import RedisConfig

            self._client = redis.Redis(
                host=RedisConfig.HOST,
                port=RedisConfig.PORT,
                db=RedisConfig.DB,
                password=RedisConfig.PASSWORD,
                decode_responses=True,
                socket_connect_timeout=RedisConfig.CONNECT_TIMEOUT,
                socket_timeout=RedisConfig.SOCKET_TIMEOUT
            )
            self._client.ping()
            self._use_redis = True
            logger.info("Redis cache connected")
        except Exception as e:
            # Fall back silently (keep startup logs clean in local mode).
            logger.info(f"Redis is enabled but unavailable; using in-memory cache instead: {e}")
            self._client = MemoryCache()
            self._use_redis = False
    
    def get(self, key: str) -> Optional[Any]:
        """获取缓存"""
        try:
            data = self._client.get(key)
            if data:
                return json.loads(data)
            return None
        except Exception as e:
            logger.error(f"Cache read failed: {e}")
            return None
    
    def set(self, key: str, value: Any, ttl: int = 300):
        """设置缓存"""
        try:
            self._client.setex(key, ttl, json.dumps(value))
        except Exception as e:
            logger.error(f"Cache write failed: {e}")
    
    def delete(self, key: str):
        """删除缓存"""
        try:
            self._client.delete(key)
        except Exception as e:
            logger.error(f"Cache delete failed: {e}")
    
    @property
    def is_redis(self) -> bool:
        return self._use_redis

