"""
Redis客户端工具模块

提供Redis缓存操作的封装，支持：
- 键值存取
- 访问计数
- IP限流检查

配置环境变量：
    python3 -m pip install redis
    export REDIS_URL="redis://127.0.0.1:6379/0"
"""
import logging
from typing import Optional, Tuple, Any

import redis

from xsdk.xutil import Xutil

logger = logging.getLogger(__name__)


class RedisClient:
    """
    Redis客户端封装类

    使用单例模式管理Redis连接，提供常用的缓存操作方法。

    Attributes:
        _client: Redis客户端实例（类级别单例）

    Example:
        >>> RedisClient.set_value("name", "test", timeout=3600)
        >>> value = RedisClient.get_value("name")
    """

    _client: Optional[redis.Redis] = None

    @classmethod
    def get_client(cls) -> Optional[redis.Redis]:
        """
        获取Redis客户端实例（单例模式）

        Returns:
            Redis客户端实例，连接失败时返回None
        """
        if cls._client is None:
            try:
                redis_url = Xutil.get_env_param("REDIS_URL")
                cls._client = redis.Redis.from_url(redis_url, decode_responses=True)
            except Exception as e:
                logger.warning(f"Failed to connect to Redis: {e}")
        return cls._client

    @staticmethod
    def set_value(key: str, value: Any, timeout: Optional[int] = None) -> bool:
        """
        设置缓存值

        Args:
            key: 缓存键
            value: 缓存值
            timeout: 过期时间（秒），None表示永不过期

        Returns:
            操作是否成功
        """
        client = RedisClient.get_client()
        if client is None:
            return False
        try:
            client.set(key, value, ex=timeout)
            return True
        except Exception as e:
            logger.warning(f"Failed to set value for key '{key}': {e}")
            return False

    @staticmethod
    def get_value(key: str) -> Optional[str]:
        """
        获取缓存值

        Args:
            key: 缓存键

        Returns:
            缓存值，不存在或异常时返回None
        """
        RedisClient.count(key)
        client = RedisClient.get_client()
        if client is None:
            return None
        try:
            return client.get(key)
        except Exception as e:
            logger.warning(f"Failed to get value for key '{key}': {e}")
            return None

    @staticmethod
    def count(key: str) -> int:
        """
        增加键的访问计数

        Args:
            key: 缓存键

        Returns:
            当前计数值，异常时返回0
        """
        client = RedisClient.get_client()
        if client is None:
            return 0
        try:
            count_key = f"COUNT_{key}"
            return client.incr(count_key)
        except Exception as e:
            logger.warning(f"Failed to increment count for key '{key}': {e}")
            return 0

    @staticmethod
    def check_ip_count(ip: str, max_count: int = 10) -> Tuple[bool, Optional[str]]:
        """
        检查IP访问次数是否超限

        Args:
            ip: IP地址
            max_count: 最大允许访问次数

        Returns:
            (是否允许访问, 错误消息)
            - (True, None): 允许访问
            - (False, 错误消息): 超过限制
        """
        client = RedisClient.get_client()
        if client is None:
            return True, None

        key = f"IP_{ip}"
        try:
            curr_count = client.incr(key)
            if curr_count > max_count:
                return False, f"您（{ip}）已访问超过{max_count}次，请在24小时后重试～"
            return True, None
        except Exception as e:
            logger.warning(f"Failed to check IP count for '{ip}': {e}")
            return True, None

    @staticmethod
    def reset_ip_count(ip: str, default_count: int = 0) -> bool:
        """
        重置IP访问计数

        Args:
            ip: IP地址
            default_count: 重置后的计数值

        Returns:
            操作是否成功
        """
        client = RedisClient.get_client()
        if client is None:
            return False

        key = f"IP_{ip}"
        try:
            client.set(key, default_count)
            return True
        except Exception as e:
            logger.warning(f"Failed to reset IP count for '{ip}': {e}")
            return False


if __name__ == '__main__':
    key = "name"
    value = "test"
    RedisClient.set_value(key, value)
    res = RedisClient.get_value(key)
    print(res)
