"""
Redis 命令解析与安全检查：分类（只读/写/危险）、是否需 confirm。
"""
from __future__ import annotations

from dataclasses import dataclass

# 只读命令（不修改数据）
READ_ONLY = frozenset({
    "GET", "MGET", "GETRANGE", "GETSET",  # 若视为写则可移出
    "EXISTS", "TYPE", "TTL", "PTTL", "OBJECT",
    "SCAN", "HSCAN", "SSCAN", "ZSCAN",
    "HGET", "HGETALL", "HMGET", "HKEYS", "HVALS", "HLEN", "HEXISTS",
    "LRANGE", "LLEN", "LINDEX",
    "SMEMBERS", "SISMEMBER", "SCARD", "SRANDMEMBER",
    "ZRANGE", "ZRANGEBYSCORE", "ZRANK", "ZREVRANK", "ZCARD", "ZSCORE", "ZCOUNT",
    "INFO", "PING", "TIME", "DBSIZE", "KEYS",  # KEYS 只读但危险（阻塞）
})

# 危险命令：禁止或必须 confirm
DANGEROUS = frozenset({
    "FLUSHALL", "FLUSHDB", "KEYS",  # KEYS 大 key 会阻塞
    "CONFIG", "DEBUG", "SHUTDOWN", "BGREWRITEAOF", "BGSAVE",
    "CLUSTER", "MODULE", "REPLICAOF", "SAVE", "LASTSAVE",
})

# 写命令（修改数据）
WRITE = frozenset({
    "SET", "SETEX", "SETNX", "PSETEX", "GETDEL", "GETEX",
    "DEL", "UNLINK", "EXPIRE", "PEXPIRE", "EXPIREAT", "PEXPIREAT", "PERSIST",
    "INCR", "DECR", "INCRBY", "DECRBY", "INCRBYFLOAT", "APPEND",
    "HSET", "HSETNX", "HMSET", "HDEL", "HINCRBY", "HINCRBYFLOAT",
    "LPUSH", "RPUSH", "LPOP", "RPOP", "LREM", "LSET", "LTRIM", "RPOPLPUSH", "LMOVE", "BLMOVE",
    "SADD", "SREM", "SPOP", "SINTERSTORE", "SUNIONSTORE", "SDIFFSTORE", "SMOVE",
    "ZADD", "ZREM", "ZINCRBY", "ZPOPMIN", "ZPOPMAX", "ZREMRANGEBYRANK", "ZREMRANGEBYSCORE", "ZREMRANGEBYLEX",
    "RENAME", "RENAMENX", "COPY", "RESTORE", "MIGRATE",
    "PUBLISH", "SCRIPT", "EVAL", "EVALSHA",
})


@dataclass
class CommandAnalysis:
    """单条命令分析结果"""
    command: str
    args: list[str]
    is_read: bool
    is_write: bool
    is_dangerous: bool
    need_confirm: bool
    message: str


def normalize_command(cmd: str) -> str:
    """命令名转大写。"""
    return (cmd or "").strip().upper()


def parse_command(payload: str) -> tuple[str, list[str]]:
    """
    简单解析：首词为命令，其余为参数。
    若 payload 为 "GET foo" 返回 ("GET", ["foo"])；"SET k v" 返回 ("SET", ["k", "v"])。
    """
    parts = (payload or "").strip().split()
    if not parts:
        return "", []
    return normalize_command(parts[0]), parts[1:]


def analyze_command(payload: str, read_only: bool) -> CommandAnalysis:
    """
    分析一条 Redis 命令（由大模型产生），返回是否只读、是否危险、是否需要 confirm。
    """
    command, args = parse_command(payload)
    if not command:
        return CommandAnalysis(
            command="",
            args=[],
            is_read=False,
            is_write=False,
            is_dangerous=False,
            need_confirm=True,
            message="空命令，不执行。",
        )
    is_read = command in READ_ONLY and command not in DANGEROUS
    is_write = command in WRITE
    is_dangerous = command in DANGEROUS
    need_confirm = False
    message = ""
    if read_only and (is_write or is_dangerous):
        need_confirm = False
        message = "当前为只读模式，拒绝执行写操作或危险命令。"
    elif is_dangerous:
        if command == "KEYS":
            message = "KEYS 可能阻塞，建议使用 SCAN；若确需执行请传入 confirm=true。"
            need_confirm = True
        else:
            message = f"{command} 为危险命令，禁止通过 MCP 执行，请在 Redis 客户端中手动操作。"
            need_confirm = False  # 直接禁止
    elif is_write:
        message = "写操作，需传入 confirm=true 后执行。"
        need_confirm = True
    elif is_read:
        message = "只读命令，可直接执行。"
    else:
        message = f"未识别的命令 {command}，需传入 confirm=true 后执行。"
        need_confirm = True
    return CommandAnalysis(
        command=command,
        args=args,
        is_read=is_read,
        is_write=is_write,
        is_dangerous=is_dangerous,
        need_confirm=need_confirm,
        message=message,
    )
