"""Redis 缓存服务层。

提供统一的缓存读写接口，供各 API 端点使用：
- 品牌列表（TTL: 5 分钟）
- 仪表盘统计数据（TTL: 2 分钟）
- 用户配置信息（TTL: 10 分钟）
"""
import json
import logging
from typing import Any

import redis.asyncio as aioredis

from app.config import settings

logger = logging.getLogger(__name__)

# TTL 常量（秒）
TTL_BRANDS = 300        # 5 分钟
TTL_DASHBOARD = 120     # 2 分钟
TTL_USER_PROFILE = 600  # 10 分钟


class CacheService:
    """异步 Redis 缓存服务。"""

    def __init__(self) -> None:
        self._redis: aioredis.Redis | None = None

    @property
    def redis(self) -> aioredis.Redis:
        if self._redis is None:
            self._redis = aioredis.from_url(
                settings.REDIS_URL,
                encoding="utf-8",
                decode_responses=True,
            )
        return self._redis

    async def get(self, key: str) -> str | None:
        """从缓存读取字符串值，不存在或出错时返回 None。"""
        try:
            return await self.redis.get(key)
        except Exception as exc:
            logger.warning("Cache GET failed for key=%s: %s", key, exc)
            return None

    async def get_json(self, key: str) -> Any | None:
        """从缓存读取并反序列化 JSON 值。"""
        raw = await self.get(key)
        if raw is None:
            return None
        try:
            return json.loads(raw)
        except json.JSONDecodeError:
            return None

    async def set(self, key: str, value: str, expire: int = 300) -> None:
        """写入缓存字符串值，expire 单位为秒。"""
        try:
            await self.redis.set(key, value, ex=expire)
        except Exception as exc:
            logger.warning("Cache SET failed for key=%s: %s", key, exc)

    async def set_json(self, key: str, value: Any, expire: int = 300) -> None:
        """序列化为 JSON 后写入缓存。"""
        try:
            await self.set(key, json.dumps(value, default=str), expire=expire)
        except Exception as exc:
            logger.warning("Cache SET_JSON failed for key=%s: %s", key, exc)

    async def delete(self, key: str) -> None:
        """删除指定缓存键。"""
        try:
            await self.redis.delete(key)
        except Exception as exc:
            logger.warning("Cache DELETE failed for key=%s: %s", key, exc)

    async def invalidate_pattern(self, pattern: str) -> int:
        """批量删除匹配 pattern 的所有缓存键，返回删除数量。"""
        try:
            keys = await self.redis.keys(pattern)
            if keys:
                return await self.redis.delete(*keys)
            return 0
        except Exception as exc:
            logger.warning("Cache INVALIDATE_PATTERN failed for pattern=%s: %s", pattern, exc)
            return 0

    async def close(self) -> None:
        """关闭 Redis 连接。"""
        if self._redis is not None:
            await self._redis.aclose()
            self._redis = None


# 模块级单例（懒加载，应用启动后自动创建连接池）
_cache_service: CacheService | None = None


def get_cache_service() -> CacheService:
    """获取全局缓存服务单例。"""
    global _cache_service
    if _cache_service is None:
        _cache_service = CacheService()
    return _cache_service
