/**
 * Project Caffeine
 * Copyright (c) 2025-2026 Gitconomy Research
 *
 * SPDX-License-Identifier: MIT
 * 
 * Contributors:
 * - 郭晧 <guohao@gitconomy.org> (Initial Author)
 */

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
import { generate5Whys } from './services/promptService';
import { listObsidianNotes, readObsidianNote } from './services/resourceService';
import * as fs from 'fs';
import * as path from 'path';

// ==========================================
// 1. 初始化 MCP Server
// ==========================================
const mcpServer = new McpServer({
    name: "Project-Caffeine-Prompt-Strategy",
    version: "1.2.0"
});

// ==========================================
// 2. 注册 Tools (工具) - 赋予大模型主动执行的能力
// ==========================================

// 工具 1：5 Whys 提示词策略生成
mcpServer.tool(
    "generate_5_whys",
    "使用 5 Whys 模板对用户查询进行深度分解，生成增强的提示词策略",
    { query: z.string().describe("需要分析的查询主题") },
    async ({ query }: { query: string }) => {
        console.error(`[Project Caffeine] 大模型调用工具: 正在生成 5 Whys 策略 -> ${query}`);
        const enhancedPrompt = generate5Whys(query);
        return {
            content: [{ type: "text", text: JSON.stringify(enhancedPrompt, null, 2) }]
        };
    }
);

// 工具 2：扫描本地知识库目录
mcpServer.tool(
    "list_local_notes",
    "获取本地 Obsidian 知识库中的所有 Markdown 笔记列表，用于了解当前有哪些可用的本地上下文资料。",
    {}, 
    async () => {
        console.error(`[Project Caffeine] 大模型调用工具: 正在扫描本地笔记列表...`);
        const notes = await listObsidianNotes();
        return {
            content: [{ 
                type: "text", 
                text: notes.length > 0 ? `找到了以下笔记：\n${notes.join('\n')}` : "未找到笔记。"
            }]
        };
    }
);

// 工具 3：阅读指定的单篇笔记内容
mcpServer.tool(
    "read_local_note",
    "读取本地 Obsidian 知识库中指定笔记的完整内容，作为深度分析的上下文参考。",
    { filename: z.string().describe("需要读取的笔记文件名，必须包含 .md 后缀") },
    async ({ filename }: { filename: string }) => {
        console.error(`[Project Caffeine] 大模型调用工具: 正在深度阅读笔记 -> ${filename}`);
        try {
            const content = await readObsidianNote(filename);
            return { content: [{ type: "text", text: content }] };
        } catch (error: any) {
            return {
                content: [{ type: "text", text: `读取失败: ${error.message}` }],
                isError: true // 明确告知大模型此操作抛出了错误
            };
        }
    }
);

// ==========================================
// 3. 注册 Resources (资源) - 暴露给客户端供用户手动勾选的静态数据
// ==========================================

// 资源 1：知识库目录索引
mcpServer.resource(
    "obsidian-index",                   // 客户端显示的资源 Name/ID
    "obsidian://vault/index",           // 唯一的 URI 标识
    { 
        description: "本地知识库的目录索引，包含所有 Markdown 笔记的列表" 
    },
    async (uri) => {
        console.error(`[Project Caffeine] 客户端请求静态资源: ${uri.href}`);
        
        const notes = await listObsidianNotes();
        const textContent = notes.length > 0 
            ? `当前知识库包含以下文件：\n${notes.join('\n')}` 
            : "当前知识库为空。";

        return {
            contents: [{
                uri: uri.href,
                mimeType: "text/plain",
                text: textContent
            }]
        };
    }
);

// ==========================================
// 4. 启动底层 Stdio 传输层
// ==========================================
async function start(): Promise<void> {
    console.error("[Project Caffeine] 正在启动 TS 版 MCP Server (含 Tools 与 Resources)...");
    const transport = new StdioServerTransport();
    await mcpServer.connect(transport);
    console.error("[Project Caffeine] MCP Server 已就绪，等待 Cherry Studio 交互。");
}

// 捕获致命错误并安全退出
start().catch((err: unknown) => {
    console.error("服务器启动失败:", err);
    process.exit(1);
});

// ==========================================
// 💡 5. 日志持久化拦截器 (Linux)
// ==========================================
const logFilePath = path.resolve(__dirname, '../server.log');
const originalConsoleError = console.error;

console.error = (...args) => {
    // 1. 在后台输出
    originalConsoleError(...args);
    // 2. 同时把日志追加写入到项目根目录的 server.log 文件中
    const logMessage = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
    fs.appendFileSync(logFilePath, `[${new Date().toISOString()}] ${logMessage}\n`);
};