import { readFile, readdir } from 'node:fs/promises';
import { join } from 'node:path';
import { getResourceSearchPaths } from '../utils/resourcePaths.js';
const pluginCache = new Map();
let discoveryDone = false;
function stripQuotes(s) {
    const trimmed = s.trim();
    if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
        (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
        return trimmed.slice(1, -1);
    }
    return trimmed;
}
/**
 * 跨平台取路径最后一段。Windows 上 join() 产出反斜杠路径，单纯 split('/')
 * 不切分会让整条绝对路径变成"目录名"。同时吃 \\ 与 /，与
 * hookEngine.pluginNameFromRoot 的归一逻辑保持一致。
 */
export function baseName(p) {
    const parts = p.replace(/[\\/]+$/, '').split(/[\\/]/);
    return parts[parts.length - 1] || p;
}
function parseMarkdownFrontmatter(content) {
    const match = content.match(/^---\n([\s\S]*?)\n---/);
    if (!match)
        return {};
    const frontmatter = {};
    for (const line of match[1].split('\n')) {
        const colon = line.indexOf(':');
        if (colon < 0)
            continue;
        const key = line.slice(0, colon).trim();
        const value = line.slice(colon + 1).trim();
        if (key)
            frontmatter[key] = stripQuotes(value);
    }
    return frontmatter;
}
async function loadPlugin(pluginDirPath) {
    const dirName = baseName(pluginDirPath);
    const manifestPath = join(pluginDirPath, '.claude-plugin', 'plugin.json');
    let manifestName = dirName;
    let manifestVersion;
    let manifestDesc;
    try {
        const raw = await readFile(manifestPath, 'utf8');
        const parsed = JSON.parse(raw);
        manifestName = parsed.name ?? dirName;
        manifestVersion = parsed.version;
        manifestDesc = parsed.description;
    }
    catch {
    }
    const commandsDir = join(pluginDirPath, 'commands');
    const commands = [];
    try {
        const entries = await readdir(commandsDir, { withFileTypes: true });
        for (const entry of entries) {
            if (!entry.name.endsWith('.md'))
                continue;
            const cmdPath = join(commandsDir, entry.name);
            try {
                const content = await readFile(cmdPath, 'utf8');
                const fm = parseMarkdownFrontmatter(content);
                const sep = content.indexOf('\n---', 4);
                const body = sep >= 0 ? content.slice(sep + 4).trim() : content.trim();
                commands.push({
                    name: entry.name.replace(/\.md$/, ''),
                    description: fm.description ?? '(no description)',
                    argumentHint: fm['argument-hint'],
                    pluginName: manifestName,
                    pluginRoot: pluginDirPath,
                    promptBody: body,
                });
            }
            catch {
            }
        }
    }
    catch {
    }
    const hooksJsonPath = join(pluginDirPath, 'hooks', 'hooks.json');
    let hasStopHook = false;
    try {
        const hooksRaw = await readFile(hooksJsonPath, 'utf8');
        const hooksParsed = JSON.parse(hooksRaw);
        const stopHooks = hooksParsed?.hooks?.Stop;
        if (Array.isArray(stopHooks) && stopHooks.length > 0) {
            hasStopHook = true;
        }
    }
    catch {
    }
    if (commands.length === 0 && !hasStopHook)
        return null;
    return {
        name: manifestName,
        version: manifestVersion,
        description: manifestDesc,
        root: pluginDirPath,
        commands,
        hasStopHook,
    };
}
export async function discoverPlugins() {
    if (discoveryDone && pluginCache.size > 0) {
        return Array.from(pluginCache.values());
    }
    pluginCache.clear();
    discoveryDone = true;
    // 双源扫描：cwd 优先 + packageRoot fallback；按数组顺序处理，已有 manifestName 跳过
    const searchPaths = getResourceSearchPaths('plugins', import.meta.url);
    // 命令名 → 首个声明它的插件名。resolveCommand 按插入顺序返回第一个命中，
    // 所以两个不同插件声明同名命令时，先注册者生效、后者被影 —— 不再静默，warn 一次。
    const commandOwners = new Map();
    for (const root of searchPaths) {
        try {
            const entries = await readdir(root, { withFileTypes: true });
            for (const entry of entries) {
                if (!entry.isDirectory())
                    continue;
                if (entry.name.startsWith('.'))
                    continue;
                const plugin = await loadPlugin(join(root, entry.name));
                if (!plugin)
                    continue;
                if (pluginCache.has(plugin.name))
                    continue; // cwd 已注册的 manifestName，packageRoot 同名跳过
                pluginCache.set(plugin.name, plugin);
                for (const cmd of plugin.commands) {
                    const owner = commandOwners.get(cmd.name);
                    if (owner && owner !== plugin.name) {
                        console.warn(`[minimal-agent] 命令名冲突：/${cmd.name} 同时由插件 "${owner}" 与 "${plugin.name}" 声明；` +
                            `先注册的 "${owner}" 生效，"${plugin.name}" 的同名命令被忽略。`);
                    }
                    else if (!owner) {
                        commandOwners.set(cmd.name, plugin.name);
                    }
                }
            }
        }
        catch {
        }
    }
    return Array.from(pluginCache.values());
}
/** 仅供测试：重置 discovery cache。 */
export function _resetPluginCache() {
    pluginCache.clear();
    discoveryDone = false;
}
export function resolveCommand(input) {
    const trimmed = input.trimStart();
    if (!trimmed.startsWith('/'))
        return null;
    const spaceIdx = trimmed.indexOf(' ', 1);
    const cmdName = spaceIdx >= 0 ? trimmed.slice(1, spaceIdx) : trimmed.slice(1);
    const args = spaceIdx >= 0 ? trimmed.slice(spaceIdx + 1) : '';
    for (const plugin of pluginCache.values()) {
        for (const cmd of plugin.commands) {
            if (cmd.name === cmdName) {
                return { cmd, arguments: args };
            }
        }
    }
    return null;
}
export function buildCommandInput(resolved) {
    const { cmd, arguments: args } = resolved;
    let input = cmd.promptBody;
    input = input.replaceAll('${CLAUDE_PLUGIN_ROOT}', cmd.pluginRoot);
    // 模板是否自己引用了参数占位符。引用了就别再补尾注，否则参数出现两遍。
    const hadArgsPlaceholder = input.includes('$ARGUMENTS') || input.includes('${ARGUMENTS}');
    input = input.replaceAll('$ARGUMENTS', args);
    input = input.replaceAll('${ARGUMENTS}', args);
    if (!hadArgsPlaceholder && args.trim()) {
        input += `\n\n用户参数: ${args.trim()}`;
    }
    return input;
}
export function listAvailableCommands() {
    const result = [];
    for (const plugin of pluginCache.values()) {
        for (const cmd of plugin.commands) {
            result.push({
                command: `/${cmd.name}`,
                plugin: plugin.name,
                description: cmd.description,
            });
        }
    }
    return result;
}
