/**
 * MCP Server command — starts a stdio-based MCP server
 *
 * Exposes Quickback documentation and project context to any MCP-compatible AI tool
 * (Claude Desktop, Cursor, VS Code Copilot, Windsurf, etc.)
 *
 * Usage:
 *   quickback mcp              # Start stdio MCP server
 *
 * Configuration (claude_desktop_config.json or .cursor/mcp.json):
 *   {
 *     "mcpServers": {
 *       "quickback": {
 *         "command": "npx",
 *         "args": ["@quickback-dev/cli", "mcp"]
 *       }
 *     }
 *   }
 */
import { DOCS, TOPIC_LIST } from "../docs/content.js";
import { promises as fs } from "fs";
import { join } from "path";
export async function mcp() {
    const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
    const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
    const { z } = await import("zod");
    const server = new McpServer({
        name: "quickback",
        version: "1.0.0",
    });
    // --- Documentation Resources ---
    // Each doc topic is available as a readable resource
    for (const topic of TOPIC_LIST) {
        const doc = DOCS[topic];
        if (!doc)
            continue;
        server.resource(topic, `quickback://docs/${topic}`, { description: doc.title, mimeType: "text/markdown" }, async () => ({
            contents: [
                {
                    uri: `quickback://docs/${topic}`,
                    text: `# ${doc.title}\n\n${doc.content}`,
                    mimeType: "text/markdown",
                },
            ],
        }));
    }
    // --- Documentation Tools ---
    server.tool("list_topics", "List all available Quickback documentation topics", {}, async () => {
        const grouped = {};
        for (const topic of TOPIC_LIST) {
            const section = topic.split("/")[0];
            if (!grouped[section])
                grouped[section] = [];
            grouped[section].push(topic);
        }
        let output = "# Quickback Documentation Topics\n\n";
        for (const [section, topics] of Object.entries(grouped)) {
            output += `## ${section}\n`;
            for (const t of topics) {
                const doc = DOCS[t];
                output += `- **${t}** — ${doc?.title || t}\n`;
            }
            output += "\n";
        }
        return { content: [{ type: "text", text: output }] };
    });
    // @ts-ignore — TS2589 deep instantiation from MCP SDK generics
    server.tool("get_doc", "Get a specific Quickback documentation topic by key. Supports fuzzy suffix matching (e.g., 'firewall' matches 'compiler/definitions/firewall').", { topic: z.string().describe("Topic key or short name (e.g., 'firewall', 'compiler/definitions/firewall')") }, async ({ topic }) => {
        // Exact match first
        let resolved = DOCS[topic] ? topic : null;
        // Fuzzy suffix match
        if (!resolved) {
            const matches = TOPIC_LIST.filter((t) => t === topic || t.endsWith(`/${topic}`));
            if (matches.length === 1) {
                resolved = matches[0];
            }
            else if (matches.length > 1) {
                return {
                    content: [
                        {
                            type: "text",
                            text: `Ambiguous topic "${topic}". Did you mean one of:\n${matches.map((m) => `- ${m}`).join("\n")}`,
                        },
                    ],
                };
            }
        }
        if (!resolved || !DOCS[resolved]) {
            return {
                content: [
                    {
                        type: "text",
                        text: `Topic "${topic}" not found. Use list_topics to see all available topics.`,
                    },
                ],
            };
        }
        const doc = DOCS[resolved];
        return {
            content: [
                {
                    type: "text",
                    text: `# ${doc.title}\n\n${doc.content}`,
                },
            ],
        };
    });
    server.tool("search_docs", "Search Quickback documentation content by keyword. Returns matching topics with relevant excerpts.", { query: z.string().describe("Search query (case-insensitive)") }, async ({ query }) => {
        const lower = query.toLowerCase();
        const results = [];
        for (const topic of TOPIC_LIST) {
            const doc = DOCS[topic];
            if (!doc)
                continue;
            const content = doc.content.toLowerCase();
            const title = doc.title.toLowerCase();
            if (content.includes(lower) || title.includes(lower)) {
                // Extract excerpt around first match
                const idx = content.indexOf(lower);
                const start = Math.max(0, idx - 100);
                const end = Math.min(content.length, idx + lower.length + 100);
                const excerpt = (start > 0 ? "..." : "") +
                    doc.content.substring(start, end).replace(/\n/g, " ") +
                    (end < content.length ? "..." : "");
                results.push({ topic, title: doc.title, excerpt });
            }
        }
        if (results.length === 0) {
            return {
                content: [
                    {
                        type: "text",
                        text: `No results found for "${query}".`,
                    },
                ],
            };
        }
        let output = `# Search results for "${query}" (${results.length} matches)\n\n`;
        for (const r of results.slice(0, 20)) {
            output += `## ${r.topic}\n**${r.title}**\n${r.excerpt}\n\n`;
        }
        if (results.length > 20) {
            output += `\n*...and ${results.length - 20} more results*\n`;
        }
        return { content: [{ type: "text", text: output }] };
    });
    // --- Project-Aware Tools ---
    server.tool("read_config", "Read the current project's quickback.config.ts file. Returns the raw TypeScript source.", {}, async () => {
        const configPath = await findProjectFile([
            "quickback/quickback.config.ts",
            "quickback.config.ts",
        ]);
        if (!configPath) {
            return {
                content: [
                    {
                        type: "text",
                        text: "No quickback.config.ts found. Not in a Quickback project directory.",
                    },
                ],
            };
        }
        const source = await fs.readFile(configPath, "utf-8");
        return {
            content: [
                {
                    type: "text",
                    text: `# quickback.config.ts\n\n\`\`\`typescript\n${source}\n\`\`\``,
                },
            ],
        };
    });
    server.tool("list_features", "List all features defined in the current Quickback project. Shows feature directories and their table definition files.", {}, async () => {
        const featuresDir = await findProjectDir([
            "quickback/features",
            "features",
        ]);
        if (!featuresDir) {
            return {
                content: [
                    {
                        type: "text",
                        text: "No features directory found. Not in a Quickback project directory.",
                    },
                ],
            };
        }
        const entries = await fs.readdir(featuresDir, { withFileTypes: true });
        const features = [];
        for (const entry of entries) {
            if (!entry.isDirectory())
                continue;
            const featureDir = join(featuresDir, entry.name);
            const files = await fs.readdir(featureDir);
            features.push({
                name: entry.name,
                files: files.filter((f) => f.endsWith(".ts")),
            });
        }
        if (features.length === 0) {
            return {
                content: [
                    {
                        type: "text",
                        text: "Features directory exists but contains no feature definitions.",
                    },
                ],
            };
        }
        let output = `# Project Features (${features.length})\n\n`;
        for (const f of features) {
            output += `## ${f.name}/\n`;
            for (const file of f.files) {
                output += `- ${file}\n`;
            }
            output += "\n";
        }
        return { content: [{ type: "text", text: output }] };
    });
    server.tool("read_feature", "Read the source code of a specific feature. Returns all .ts files in the feature directory.", {
        feature: z.string().describe("Feature name (directory name under quickback/features/)"),
    }, async ({ feature }) => {
        const featuresDir = await findProjectDir([
            "quickback/features",
            "features",
        ]);
        if (!featuresDir) {
            return {
                content: [
                    {
                        type: "text",
                        text: "No features directory found. Not in a Quickback project directory.",
                    },
                ],
            };
        }
        const featureDir = join(featuresDir, feature);
        try {
            await fs.access(featureDir);
        }
        catch {
            return {
                content: [
                    {
                        type: "text",
                        text: `Feature "${feature}" not found. Use list_features to see available features.`,
                    },
                ],
            };
        }
        const files = (await fs.readdir(featureDir)).filter((f) => f.endsWith(".ts"));
        let output = `# Feature: ${feature}\n\n`;
        for (const file of files) {
            const source = await fs.readFile(join(featureDir, file), "utf-8");
            output += `## ${file}\n\n\`\`\`typescript\n${source}\n\`\`\`\n\n`;
        }
        // Check for handlers/ subdirectory
        const handlersDir = join(featureDir, "handlers");
        try {
            const handlerFiles = (await fs.readdir(handlersDir)).filter((f) => f.endsWith(".ts"));
            for (const file of handlerFiles) {
                const source = await fs.readFile(join(handlersDir, file), "utf-8");
                output += `## handlers/${file}\n\n\`\`\`typescript\n${source}\n\`\`\`\n\n`;
            }
        }
        catch {
            // No handlers directory
        }
        return { content: [{ type: "text", text: output }] };
    });
    server.tool("read_schema_registry", "Read the project's compiled schema-registry.json. Contains full metadata about all tables, columns, security rules, views, and actions.", {}, async () => {
        const registryPath = await findProjectFile([
            "src/schema-registry.json",
            "dist/schema-registry.json",
            "schema-registry.json",
        ]);
        if (!registryPath) {
            return {
                content: [
                    {
                        type: "text",
                        text: "No schema-registry.json found. Run 'quickback compile' to generate it.",
                    },
                ],
            };
        }
        const content = await fs.readFile(registryPath, "utf-8");
        return {
            content: [
                {
                    type: "text",
                    text: `# Schema Registry\n\n\`\`\`json\n${content}\n\`\`\``,
                },
            ],
        };
    });
    // --- Helpers ---
    async function findProjectFile(candidates) {
        const cwd = process.cwd();
        for (const candidate of candidates) {
            const full = join(cwd, candidate);
            try {
                await fs.access(full);
                return full;
            }
            catch {
                // Not found, try next
            }
        }
        return null;
    }
    async function findProjectDir(candidates) {
        const cwd = process.cwd();
        for (const candidate of candidates) {
            const full = join(cwd, candidate);
            try {
                const stat = await fs.stat(full);
                if (stat.isDirectory())
                    return full;
            }
            catch {
                // Not found, try next
            }
        }
        return null;
    }
    // --- Start Server ---
    const transport = new StdioServerTransport();
    await server.connect(transport);
}
//# sourceMappingURL=mcp.js.map