package com.gzzm.lobster.tool.builtin;

import com.gzzm.lobster.tool.BuiltinToolDefinition;
import com.gzzm.lobster.tool.ToolDefinitionConfig;
import com.gzzm.lobster.tool.ToolDefinitionConfigDao;
import com.gzzm.lobster.tool.ToolRegistry;
import com.gzzm.lobster.tool.mcp.McpToolBridge;
import com.gzzm.platform.commons.Tools;
import net.cyan.nest.annotation.Inject;

import java.util.Date;

/**
 * BuiltinToolRegistrar —— 内置工具一键注册 /
 * One-shot registrar for all built-in tools.
 *
 * <p>应用启动时由 bootstrap 代码调用 {@link #registerAll()}。
 * Call once during bootstrap to populate the ToolRegistry.
 *
 * <p>注册包含两步：
 * <ol>
 *     <li>把执行器塞进内存 {@link ToolRegistry}（LLM 运行时读这里）；</li>
 *     <li>把工具元信息 upsert 进 {@code AI_TOOL_DEFINITION} 治理表
 *     （Admin UI / {@link com.gzzm.lobster.api.admin.AdminToolApi} 读这里）。</li>
 * </ol>
 * 两条路径必须同步，否则会出现"LLM 能调但 Admin 看不见"或反之。
 */
public class BuiltinToolRegistrar {

    @Inject private ToolRegistry toolRegistry;
    @Inject private WorkspaceResourceTools workspaceResourceTools;
    @Inject private MemoryTools memoryTools;
    @Inject private SkillTools skillTools;
    @Inject private InteractionTools interactionTools;
    @Inject private OaFileTools oaFileTools;
    @Inject private OaKnowledgeTools oaKnowledgeTools;
    @Inject private OaMailTools oaMailTools;
    @Inject private PlanTools planTools;
    @Inject private LongDocumentTools longDocumentTools;
    @Inject private CodeExecTool codeExecTool;
    @Inject private ReadToolResultTool readToolResultTool;
    @Inject private McpToolBridge mcpToolBridge;

    public void registerAll() {
        // 每个工具独立 try-catch：一个失败不影响其它；打明显日志让启动问题可追.
        safeRegister("workspace_tools", workspaceResourceTools);
        safeRegister("memory_tools",    memoryTools);
        safeRegister("skill_tools",     skillTools);
        safeRegister("interaction_tools", interactionTools);
        safeRegister("oa_file_tools",   oaFileTools);
        safeRegister("oa_knowledge_tools", oaKnowledgeTools);
        safeRegister("oa_mail_tools", oaMailTools);
        safeRegister("plan_tools",      planTools);
        safeRegister("long_document_tools", longDocumentTools);
        safeRegister("code_exec",       codeExecTool);
        safeRegister("read_externalized_content", readToolResultTool);
        int total = toolRegistry.all().size();
        Tools.log("[BuiltinToolRegistrar] in-memory registration done — total tools: " + total);
        // MCP tools: discover once at startup, then keep remote listTools fresh in background.
        if (mcpToolBridge != null) {
            try {
                mcpToolBridge.refresh();
                mcpToolBridge.startAutoRefresh();
            } catch (Throwable t) {
                try { Tools.log("[BuiltinToolRegistrar] MCP discovery startup failed", t); }
                catch (Throwable ignore) { /* ignore */ }
            }
        }
        // 把内置工具同步进治理表，Admin UI 才看得见
        syncToGovernanceTable();
    }

    private void safeRegister(String label, Object target) {
        if (target == null) {
            Tools.log("[BuiltinToolRegistrar] ⚠ " + label + " bean is null — nest DI 未注入，跳过");
            return;
        }
        try {
            // 通过反射调 registerTo —— 各工具类没有公共接口，走 duck typing
            target.getClass().getMethod("registerTo", ToolRegistry.class).invoke(target, toolRegistry);
            Tools.log("[BuiltinToolRegistrar] ok: " + label + " (" + target.getClass().getSimpleName() + ")");
        } catch (Throwable t) {
            try { Tools.log("[BuiltinToolRegistrar] ⚠ register failed: " + label, t); }
            catch (Throwable ignore) { /* ignore */ }
        }
    }

    /**
     * Upsert each registered built-in into {@code AI_TOOL_DEFINITION}.
     *
     * <p>- 不存在则新建，enabled=true、requireConfirm 取定义默认；
     * <br>- 已存在则只刷新元信息（displayName/description/category/mode/risk），
     *        保留管理员手动调过的 enabled / requireConfirm / orgId。
     * <br>- DAO 通过 {@link Tools#getBean} 现场解析，避免 thunwind DAO 的线程绑定坑
     *        （启动线程 ≠ 未来的业务线程，@Inject 缓存会踩空）。
     */
    private void syncToGovernanceTable() {
        ToolDefinitionConfigDao dao;
        try {
            dao = Tools.getBean(ToolDefinitionConfigDao.class);
        } catch (Throwable t) {
            try { Tools.log("[BuiltinToolRegistrar] resolve ToolDefinitionConfigDao failed", t); } catch (Throwable ignore) { /* ignore */ }
            return;
        }
        if (dao == null) {
            Tools.log("[BuiltinToolRegistrar] ToolDefinitionConfigDao bean is null — skip governance sync");
            return;
        }
        Date now = new Date();
        int inserted = 0, updated = 0;
        try {
            dao.deleteByName("read_tool_result");
        } catch (Throwable t) {
            try { Tools.log("[BuiltinToolRegistrar] cleanup legacy tool failed: read_tool_result", t); }
            catch (Throwable ignore) { /* ignore */ }
        }
        for (BuiltinToolDefinition def : toolRegistry.all()) {
            try {
                ToolDefinitionConfig row = dao.getByName(def.getToolName());
                boolean isNew = row == null;
                if (isNew) {
                    row = new ToolDefinitionConfig();
                    row.setToolName(def.getToolName());
                    row.setEnabled(Boolean.TRUE);
                    row.setRequireConfirm(def.isRequireConfirm());
                    row.setCreateTime(now);
                }
                row.setDisplayName(def.getDisplayName());
                row.setDescription(def.getDescription());
                row.setCategory(def.getCategory());
                row.setMode(def.getMode());
                row.setRiskLevel(def.getRiskLevel());
                row.setUpdateTime(now);
                dao.save(row);
                if (isNew) inserted++; else updated++;
            } catch (Throwable t) {
                try { Tools.log("[BuiltinToolRegistrar] sync tool failed: " + def.getToolName(), t); } catch (Throwable ignore) { /* ignore */ }
            }
        }
        Tools.log("[BuiltinToolRegistrar] governance sync done — inserted=" + inserted + ", updated=" + updated);
    }
}
