"""
ES 请求解析与安全检查：按 method + path 分类读/写/危险。
"""
from __future__ import annotations

from dataclasses import dataclass

# 只读 path 前缀（GET 或 POST _search 等）
READ_PATTERNS = (
    "_search", "_mget", "_get", "_count", "_explain",
    "_mapping", "_settings", "_aliases", "_stats", "_health",
    "_cat/", "_cluster/health", "_cluster/state", "_nodes",
)
# 危险：删整索引、改集群、关节点等
DANGEROUS_PATTERNS = (
    "/_cluster", "/_nodes", "/_snapshot", "_close",
)
# 写：index, update, delete doc, bulk
WRITE_METHODS = ("PUT", "POST", "DELETE")
WRITE_PATH_SUFFIXES = ("/_doc", "/_update", "/_bulk", "/_update_by_query", "/_delete_by_query", "/_reindex")


@dataclass
class RequestAnalysis:
    method: str
    path: str
    body: dict | None
    is_read: bool
    is_write: bool
    is_dangerous: bool
    need_confirm: bool
    message: str


def _normalize_path(path: str) -> str:
    return (path or "").strip().rstrip("/") or "/"


def _path_is_read(path: str, method: str) -> bool:
    p = _normalize_path(path)
    if method.upper() == "GET":
        return True
    if method.upper() == "POST" and "_search" in p:
        return True
    for pref in READ_PATTERNS:
        if pref in p and not any(d in p for d in DANGEROUS_PATTERNS):
            return True
    return False


def _path_is_dangerous(path: str) -> bool:
    p = _normalize_path(path).lower()
    for d in DANGEROUS_PATTERNS:
        if d in p:
            return True
    # 删除整个索引: DELETE /index_name（无 /_doc/id）
    if p.strip("/") and p.count("/") <= 1 and not p.startswith("/_"):
        return True
    return False


def _path_is_write(path: str, method: str) -> bool:
    m = method.upper()
    if m not in WRITE_METHODS:
        return False
    p = _normalize_path(path)
    if m == "DELETE":
        return True
    for suf in WRITE_PATH_SUFFIXES:
        if suf in p:
            return True
    if m == "PUT" and "/_doc" in p:
        return True
    if m == "POST" and ("_doc" in p or "_bulk" in p or "_update" in p):
        return True
    return False


def analyze_request(method: str, path: str, body: dict | None, read_only: bool) -> RequestAnalysis:
    """分析一条 ES 请求（由大模型产生），返回是否只读/写/危险、是否需 confirm。"""
    method = (method or "GET").strip().upper()
    path = _normalize_path(path)
    is_read = _path_is_read(path, method)
    is_write = _path_is_write(path, method)
    is_dangerous = _path_is_dangerous(path) or (method == "DELETE" and path.count("/") <= 1 and len(path.strip("/")) > 0)  # 删整索引
    need_confirm = False
    message = ""
    if read_only and (is_write or is_dangerous):
        message = "当前为只读模式，拒绝执行写操作。"
    elif is_dangerous:
        message = "危险操作（如删索引、改集群），禁止通过 MCP 执行，请在 Kibana/控制台操作。"
    elif is_write:
        message = "写操作，需传入 confirm=true 后执行。"
        need_confirm = True
    elif is_read:
        message = "只读请求，可直接执行。"
    else:
        message = "未识别的请求，需传入 confirm=true 后执行。"
        need_confirm = True
    return RequestAnalysis(
        method=method,
        path=path,
        body=body,
        is_read=is_read,
        is_write=is_write,
        is_dangerous=is_dangerous,
        need_confirm=need_confirm,
        message=message,
    )
