package com.gzzm.lobster.tool;

import com.gzzm.lobster.common.LobsterException;
import com.gzzm.lobster.common.ToolCategory;
import com.gzzm.lobster.identity.UserContext;
import com.gzzm.lobster.tool.mcp.McpServerConfig;
import com.gzzm.lobster.tool.mcp.McpServerConfigDao;
import com.gzzm.lobster.tool.mcp.McpToolExposureMode;
import com.gzzm.lobster.tool.mcp.McpToolCache;
import com.gzzm.lobster.tool.mcp.McpToolCacheDao;
import com.gzzm.platform.commons.Tools;
import net.cyan.nest.annotation.Inject;

/**
 * ToolPermissionChecker —— 工具级权限校验 / Tool-level permission check.
 *
 * <p>首期策略：
 * <ul>
 * <li>必须有认证用户上下文</li>
 * <li>DESTRUCTIVE 风险工具必须当前用户未被禁用高危操作</li>
 * <li>MCP 工具受 {@code McpServerConfig.enabled} 控制</li>
 * </ul>
 * Phase-1 policy: require authenticated user; DESTRUCTIVE needs non-blocked
 * user; MCP governed by its server config.
 */
public class ToolPermissionChecker {

    @Inject private ToolDefinitionConfigDao toolDefinitionConfigDao;
    @Inject private McpServerConfigDao mcpServerConfigDao;
    @Inject private McpToolCacheDao mcpToolCacheDao;

    public void check(BuiltinToolDefinition def, UserContext user) {
        if (user == null || user.getUserId() == null) {
            throw new LobsterException("tool.permission", "Unauthenticated user cannot call tool " + def.getToolName());
        }
        checkGovernance(def);
        // 扩展点：按 role / orgId 判定额外准入策略 / Extend: role/org based policies.
    }

    private void checkGovernance(BuiltinToolDefinition def) {
        if (def == null || def.getToolName() == null) return;
        boolean mcpTool = def.getCategory() == ToolCategory.MCP;
        try {
            ToolDefinitionConfigDao toolDao = toolDefinitionConfigDao();
            if (toolDao == null) {
                if (mcpTool) {
                    throw new LobsterException("tool.governance_unavailable",
                            "Tool governance is unavailable for MCP tool " + def.getToolName());
                }
                return;
            }
            ToolDefinitionConfig row = toolDao.getByName(def.getToolName());
            if (row == null) {
                if (mcpTool) {
                    throw new LobsterException("tool.mcp_governance_missing",
                            "MCP tool governance row is missing: " + def.getToolName());
                }
                return;
            }
            if (Boolean.FALSE.equals(row.getEnabled())) {
                throw new LobsterException("tool.disabled", "Tool is disabled: " + def.getToolName());
            }
            if (row.getMcpServerId() != null && !row.getMcpServerId().isEmpty()) {
                McpServerConfig server = mcpServerConfigDao().getConfig(row.getMcpServerId());
                if (server == null || Boolean.FALSE.equals(server.getEnabled())) {
                    throw new LobsterException("tool.mcp_disabled", "MCP server is disabled: " + row.getMcpServerId());
                }
            }
            if (mcpTool) {
                McpToolCacheDao cacheDao = mcpToolCacheDao();
                if (cacheDao == null) {
                    throw new LobsterException("tool.mcp_cache_unavailable",
                            "MCP tool cache is unavailable: " + def.getToolName());
                }
                McpToolCache cache = cacheDao.getByLocalToolName(def.getToolName());
                if (cache == null) {
                    throw new LobsterException("tool.mcp_cache_missing",
                            "MCP tool cache row is missing: " + def.getToolName());
                }
                if (Boolean.FALSE.equals(cache.getEnabled())) {
                    throw new LobsterException("tool.disabled", "Tool is disabled: " + def.getToolName());
                }
                if (cache.getExposureMode() != McpToolExposureMode.DIRECT) {
                    throw new LobsterException("tool.not_exposed",
                            "MCP tool is not exposed directly: " + def.getToolName());
                }
            }
        } catch (LobsterException e) {
            throw e;
        } catch (Throwable t) {
            try { Tools.log("[ToolPermissionChecker] governance check failed", t); } catch (Throwable ignore) { /* ignore */ }
            if (mcpTool) {
                throw new LobsterException("tool.governance_unavailable",
                        "Tool governance check failed for MCP tool " + def.getToolName(), t);
            }
        }
    }

    private ToolDefinitionConfigDao toolDefinitionConfigDao() {
        try {
            ToolDefinitionConfigDao d = Tools.getBean(ToolDefinitionConfigDao.class);
            if (d != null) return d;
        } catch (Throwable ignore) { /* fallback */ }
        return toolDefinitionConfigDao;
    }

    private McpServerConfigDao mcpServerConfigDao() {
        try {
            McpServerConfigDao d = Tools.getBean(McpServerConfigDao.class);
            if (d != null) return d;
        } catch (Throwable ignore) { /* fallback */ }
        return mcpServerConfigDao;
    }

    private McpToolCacheDao mcpToolCacheDao() {
        try {
            McpToolCacheDao d = Tools.getBean(McpToolCacheDao.class);
            if (d != null) return d;
        } catch (Throwable ignore) { /* fallback */ }
        return mcpToolCacheDao;
    }
}
