import { execSync } from "node:child_process";
import { createHash } from "node:crypto";
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { getEvalModel, getProjectGroupId, readConfig, shouldEmitOtelGate, } from "../lib/config.js";
import { getEnabledExtensions } from "../lib/extension-loader.js";
import { getScm } from "../lib/scm/detect.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const packageRoot = join(__dirname, "../..");
function fileHash(path) {
    return createHash("sha256").update(readFileSync(path)).digest("hex").slice(0, 12);
}
export function registerSystemTools(server, projectRoot) {
    server.registerTool("get_system_version", {
        description: "Return the installed indusk-mcp package version",
    }, async () => {
        const pkgPath = join(packageRoot, "package.json");
        const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({ name: pkg.name, version: pkg.version }, null, 2),
                },
            ],
        };
    });
    server.registerTool("get_project_info", {
        description: "Return runtime project metadata: project_group (Graphiti group ID — sanitized form, hyphens → underscores), scm (jj or git), planning_dir, otel_role, eval_model, eval_enabled. Use `project_group` as the value for `group_ids` when querying `mcp__graphiti__*` tools — the sanitized form is what writes use, so reads must match. Always pass `[project_group, \"shared\"]` to recall both project-specific and cross-project knowledge.",
    }, async () => {
        const config = readConfig(projectRoot);
        const info = {
            project_root: projectRoot,
            project_group: getProjectGroupId(projectRoot),
            scm: getScm(projectRoot),
            planning_dir: join(projectRoot, ".indusk/planning"),
            otel_role: config?.otel?.role ?? "service",
            otel_gate_emits: shouldEmitOtelGate(projectRoot),
            eval_enabled: config?.eval?.enabled !== false,
            eval_model: getEvalModel(projectRoot),
            graphiti_group_recall_example: {
                note: "Pass `group_ids: [project_group, \"shared\"]` to graphiti queries. Omitting group_ids does NOT scan all groups — it returns empty.",
                group_ids: [getProjectGroupId(projectRoot), "shared"],
            },
        };
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify(info, null, 2),
                },
            ],
        };
    });
    server.registerTool("check_health", {
        description: "Check health of all enabled extensions. Runs health check commands from extension manifests. Errors indicate degraded system.",
    }, async () => {
        const checks = [];
        const extensions = getEnabledExtensions(projectRoot);
        for (const ext of extensions) {
            const healthChecks = ext.manifest.provides.health_checks ?? [];
            for (const check of healthChecks) {
                try {
                    const output = execSync(check.command, {
                        encoding: "utf-8",
                        timeout: 10000,
                        stdio: ["ignore", "pipe", "pipe"],
                        cwd: projectRoot,
                    }).trim();
                    checks.push({
                        name: `${ext.manifest.name}/${check.name}`,
                        status: "ok",
                        detail: output || "ok",
                    });
                }
                catch (err) {
                    const execErr = err;
                    checks.push({
                        name: `${ext.manifest.name}/${check.name}`,
                        status: "error",
                        detail: execErr.stderr?.trim() || execErr.message || "check failed",
                    });
                }
            }
        }
        if (checks.length === 0) {
            checks.push({
                name: "extensions",
                status: "ok",
                detail: "No extensions with health checks enabled. Run 'extensions enable falkordb cgc' to add checks.",
            });
        }
        const healthy = checks.every((c) => c.status === "ok");
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({ healthy, extensions: extensions.length, checks }, null, 2),
                },
            ],
            isError: !healthy,
        };
    });
    server.registerTool("get_skill_versions", {
        description: "Compare installed skills in .claude/skills/ to package skills. Returns status per skill: installed, current, or outdated.",
    }, async () => {
        const skillsSource = join(packageRoot, "skills");
        const skillsTarget = join(projectRoot, ".claude/skills");
        if (!existsSync(skillsSource)) {
            return {
                content: [
                    {
                        type: "text",
                        text: JSON.stringify({ error: "Package skills directory not found" }, null, 2),
                    },
                ],
            };
        }
        const packageSkills = readdirSync(skillsSource).filter((f) => f.endsWith(".md"));
        const skills = packageSkills.map((file) => {
            const skillName = file.replace(".md", "");
            const sourceFile = join(skillsSource, file);
            const targetFile = join(skillsTarget, skillName, "SKILL.md");
            const packageHash = fileHash(sourceFile);
            const installed = existsSync(targetFile);
            const installedHash = installed ? fileHash(targetFile) : null;
            return {
                name: skillName,
                installed,
                current: installed && packageHash === installedHash,
                packageHash,
                installedHash,
            };
        });
        const summary = {
            total: skills.length,
            installed: skills.filter((s) => s.installed).length,
            current: skills.filter((s) => s.current).length,
            outdated: skills.filter((s) => s.installed && !s.current).length,
            missing: skills.filter((s) => !s.installed).length,
        };
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({ summary, skills }, null, 2),
                },
            ],
        };
    });
    server.registerTool("get_skill_summaries", {
        description: "Returns name, description, and type for every installed skill. Use during catchup to learn what skills are available without loading full content.",
    }, async () => {
        const skillsTarget = join(projectRoot, ".claude/skills");
        if (!existsSync(skillsTarget)) {
            return {
                content: [{ type: "text", text: JSON.stringify({ skills: [], total: 0 }) }],
            };
        }
        const skillDirs = readdirSync(skillsTarget).filter((d) => !d.startsWith(".") && existsSync(join(skillsTarget, d, "SKILL.md")));
        const skills = skillDirs.map((dir) => {
            const content = readFileSync(join(skillsTarget, dir, "SKILL.md"), "utf-8");
            // Try frontmatter first (process skills)
            const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
            if (fmMatch) {
                const fm = fmMatch[1];
                const name = fm.match(/^name:\s*(.+)$/m)?.[1]?.trim() ?? dir;
                const description = fm.match(/^description:\s*(.+)$/m)?.[1]?.trim() ?? "";
                const type = fm.match(/^argument-hint:/m) ? "process" : "domain";
                return { name, description, type, slash: `/${name}` };
            }
            // Fall back to heading + first paragraph (extension skills)
            const firstPara = content
                .split("\n\n")
                .find((p) => p && !p.startsWith("#") && !p.startsWith("---"));
            const description = firstPara?.replace(/\n/g, " ").slice(0, 120) ?? "";
            return { name: dir, description, type: "extension", slash: null };
        });
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({ total: skills.length, skills }, null, 2),
                },
            ],
        };
    });
    server.registerTool("extensions_status", {
        description: "List all extensions (enabled and disabled) with their capabilities. Replaces list_domain_skills.",
    }, async () => {
        const { loadExtensions } = await import("../lib/extension-loader.js");
        const all = loadExtensions(projectRoot);
        const extensions = all.map((ext) => ({
            name: ext.manifest.name,
            description: ext.manifest.description,
            enabled: ext.enabled,
            provides: Object.keys(ext.manifest.provides),
            hasSkill: ext.manifest.provides.skill === true,
            detect: ext.manifest.detect ?? null,
        }));
        return {
            content: [
                {
                    type: "text",
                    text: JSON.stringify({
                        total: extensions.length,
                        enabled: extensions.filter((e) => e.enabled).length,
                        disabled: extensions.filter((e) => !e.enabled).length,
                        extensions,
                    }, null, 2),
                },
            ],
        };
    });
}
