"""
CMA Bot API 风险分级（L1-L4）与路由标注装饰器
=============================================

分级定义（方案文档 nexa-permission-autonomy-plan-20260828 第二节）:
    L1 只读查询       — X-BOT-KEY验证后直接放行
    L2 业务写（单条） — 放行 + 写前校验（entity归属/字段校验）
    L3 批量写/创建    — 放行 + 限制批量 + source_batch审计
    L4 危险           — 不向Bot API开放（DROP/TRUNCATE/批量DELETE/生产结构修改）

安全底线: Bot API面不存在L4端点（0项开放 = 天然隔离）。
"""
import functools

RISK_LEVELS = {
    "L1": "只读",
    "L2": "业务写",
    "L3": "批量写",
    "L4": "危险",
}

RISK_HANDLING = {
    "L1": "X-BOT-KEY验证后直接放行",
    "L2": "放行 + 写前校验（entity归属/字段校验）",
    "L3": "放行 + 限制批量 + source_batch审计",
    "L4": "不向Bot API开放（终端层拦截 + 人工审批）",
}

# ────────────────────────────────────────────────
# API → 风险级别 清单（Bot API面全量路由）
# 键格式: "METHOD path"（path 与 FastAPI route.path 一致，含 {param} 占位符）
# ────────────────────────────────────────────────
API_RISK_MAP = {
    # ── L1 只读（20项方案清单 + risk-levels查询端点） ──
    "GET /api/cma/bot/ping": "L1",
    "GET /api/cma/bot/overview": "L1",
    "GET /api/cma/bot/kpis": "L1",
    "GET /api/cma/bot/kpis/{kpi_id}/history": "L1",
    "GET /api/cma/bot/strategic-maps": "L1",
    "GET /api/cma/bot/alerts": "L1",
    "GET /api/cma/bot/budget/plans": "L1",
    "GET /api/cma/bot/cost/standard": "L1",
    "GET /api/cma/bot/cost/actual": "L1",
    "GET /api/cma/bot/actions": "L1",
    "GET /api/cma/bot/organization": "L1",
    "GET /api/cma/bot/data-sources": "L1",
    "GET /api/cma/bot/users": "L1",
    "GET /api/cma/bot/query": "L1",
    "GET /api/cma/bot/okr/list": "L1",
    "GET /api/cma/bot/nlp": "L1",
    "GET /api/cma/bot/iron-law": "L1",
    "GET /api/cma/bot/iron-law/bots": "L1",
    "GET /api/cma/bot-bridge/verify/{action_plan_id}/history": "L1",
    "GET /api/cma/bot-kpis": "L1",
    # 本任务新增的只读端点
    "GET /api/cma/bot/risk-levels": "L1",
    # ── L2 业务写（4项方案清单 + okr/create单条业务写） ──
    "POST /api/cma/bot/kpi-value-with-check": "L2",
    "POST /api/cma/bot-bridge/kpi-result": "L2",
    "POST /api/cma/bot-kpis/{kpi_id}/value": "L2",
    "POST /api/cma/bot-bridge/verify/{action_plan_id}": "L2",
    "POST /api/cma/bot/okr/create": "L2",  # 单条OKR创建（方案清单未列出，按单条业务写归类）
    # ── L3 批量写/创建（3项） ──
    "POST /api/cma/bot/import": "L3",
    "POST /api/cma/bot/kpis/create-with-links": "L3",
    "POST /api/cma/bot-bridge/mpm-result": "L3",
    # ── L4 危险：Bot API面不存在（安全底线，不添加） ──
}


def risk_level(level: str):
    """路由标注装饰器: @risk_level('L1') 挂在路由函数上（router.get/post 之下）。

    同时把级别属性写到原函数与包装函数上，保证 route.endpoint 无论取到哪个
    都能通过 getattr(endpoint, 'risk_level') 解析。
    """
    def decorator(func):
        func.risk_level = level

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)

        wrapper.risk_level = level
        return wrapper

    return decorator


def get_risk_level(method: str, path: str):
    """按 METHOD + path（FastAPI模板路径）查级别，未标注返回 None"""
    return API_RISK_MAP.get(f"{method.upper()} {path}")


def get_handling(level: str) -> str:
    """级别 → 处理方式说明"""
    return RISK_HANDLING.get(level, "")


def list_api_risk_map() -> list:
    """返回 API→级别→处理方式 清单（供 GET /api/cma/bot/risk-levels 使用）"""
    items = []
    for key, level in API_RISK_MAP.items():
        method, path = key.split(" ", 1)
        items.append({
            "method": method,
            "path": path,
            "risk_level": level,
            "handling": get_handling(level),
        })
    items.sort(key=lambda x: (x["risk_level"], x["method"], x["path"]))
    return items


def risk_summary() -> dict:
    """各级别端点数量统计"""
    summary = {lv: 0 for lv in RISK_LEVELS}
    for level in API_RISK_MAP.values():
        summary[level] = summary.get(level, 0) + 1
    return summary
