import { readFileSync, existsSync } from "fs";
import { join } from "path";
import { ValidationError } from "../utils/errors.js";
import { secureWriteFileSync, secureMkdirSync } from "../utils/secureWrite.js";
import { KASTELL_DIR, PLUGINS_NODE_MODULES } from "../utils/paths.js";
import { debugLog } from "../utils/logger.js";
import { PLUGIN_NAME_PREFIX, PLUGIN_TOOL_PREFIX } from "./sdk/constants.js";
const PLUGIN_CACHE_PATH = join(KASTELL_DIR, "plugin-manifests.json");
const PLUGIN_REGISTRY = new Map();
const usedPrefixes = new Map();
const usedCheckIds = new Set();
export function registerPlugin(manifest, checks) {
    if (PLUGIN_REGISTRY.has(manifest.name)) {
        throw new ValidationError(`Plugin "${manifest.name}" already registered`);
    }
    const prefixOwner = usedPrefixes.get(manifest.checkPrefix);
    if (prefixOwner) {
        throw new ValidationError(`checkPrefix "${manifest.checkPrefix}" already used by "${prefixOwner}"`);
    }
    for (const check of checks) {
        if (!check.id.startsWith(`${manifest.checkPrefix}-`)) {
            throw new ValidationError(`Check ID "${check.id}" must start with "${manifest.checkPrefix}-"`);
        }
        if (usedCheckIds.has(check.id)) {
            throw new ValidationError(`Check ID "${check.id}" already exists in another plugin`);
        }
    }
    usedPrefixes.set(manifest.checkPrefix, manifest.name);
    for (const check of checks) {
        usedCheckIds.add(check.id);
    }
    const checksById = new Map();
    for (const check of checks)
        checksById.set(check.id, check);
    const fixesByCheckId = new Map();
    if (manifest.fixes) {
        for (const fix of manifest.fixes)
            fixesByCheckId.set(fix.checkId, fix);
    }
    PLUGIN_REGISTRY.set(manifest.name, {
        manifest,
        checks,
        status: "loaded",
        commands: manifest.commands,
        mcpTools: manifest.mcpTools,
        fixes: manifest.fixes,
        checksById,
        fixesByCheckId,
    });
}
export function registerFailedPlugin(manifest, reason) {
    PLUGIN_REGISTRY.set(manifest.name, {
        manifest,
        checks: [],
        status: "failed",
        reason,
        checksById: new Map(),
        fixesByCheckId: new Map(),
    });
}
export function deletePlugin(name) {
    const entry = PLUGIN_REGISTRY.get(name);
    if (!entry)
        return;
    usedPrefixes.delete(entry.manifest.checkPrefix);
    for (const check of entry.checks) {
        usedCheckIds.delete(check.id);
    }
    PLUGIN_REGISTRY.delete(name);
}
export function mapRegistryPlugins(callback) {
    const results = [];
    for (const [name, entry] of PLUGIN_REGISTRY) {
        results.push(callback(name, entry));
    }
    return results;
}
export function getShortName(pluginName) {
    return pluginName.replace(PLUGIN_NAME_PREFIX, "");
}
export function getPluginCommands() {
    const entries = [];
    for (const [, entry] of PLUGIN_REGISTRY) {
        if (entry.status !== "loaded" || !entry.commands?.length)
            continue;
        const shortName = getShortName(entry.manifest.name);
        const pluginDir = join(PLUGINS_NODE_MODULES, entry.manifest.name);
        for (const cmd of entry.commands) {
            entries.push({ pluginShortName: shortName, command: cmd, pluginDir });
        }
    }
    return entries;
}
export function getPluginMcpTools() {
    const entries = [];
    for (const [, entry] of PLUGIN_REGISTRY) {
        if (entry.status !== "loaded" || !entry.mcpTools?.length)
            continue;
        const shortName = getShortName(entry.manifest.name);
        const pluginDir = join(PLUGINS_NODE_MODULES, entry.manifest.name);
        for (const tool of entry.mcpTools) {
            entries.push({
                pluginShortName: shortName,
                toolName: `${PLUGIN_TOOL_PREFIX}${shortName}_${tool.name}`,
                tool,
                pluginDir,
            });
        }
    }
    return entries;
}
export function clearPluginRegistry() {
    PLUGIN_REGISTRY.clear();
    usedPrefixes.clear();
    usedCheckIds.clear();
}
export function getPluginRegistry() {
    return PLUGIN_REGISTRY;
}
export function loadPluginCache() {
    if (!existsSync(PLUGIN_CACHE_PATH)) {
        return [];
    }
    try {
        const raw = readFileSync(PLUGIN_CACHE_PATH, "utf-8");
        const parsed = JSON.parse(raw);
        if (!Array.isArray(parsed))
            return [];
        return parsed;
    }
    catch (error) {
        debugLog?.("plugin registry read failed, creating new", { cause: error });
        return [];
    }
}
export function savePluginCache(manifests) {
    const content = JSON.stringify(manifests, null, 2);
    if (existsSync(PLUGIN_CACHE_PATH)) {
        try {
            const existing = readFileSync(PLUGIN_CACHE_PATH, "utf-8");
            if (existing === content)
                return;
        }
        catch (error) {
            debugLog?.("plugin cache comparison failed, rewriting", { cause: error });
        }
    }
    secureMkdirSync(KASTELL_DIR);
    secureWriteFileSync(PLUGIN_CACHE_PATH, content);
}
//# sourceMappingURL=registry.js.map