import fs from "node:fs";
import path from "node:path";
import { validateClaudePluginManifestJson } from "./manifest-validate.js";
const MANIFEST_SEGMENTS = [".claude-plugin", "plugin.json"];
function manifestRelPosix() {
    return MANIFEST_SEGMENTS.join("/");
}
function readDiscoveryRoots(effectiveConfig) {
    const plugins = effectiveConfig?.plugins;
    if (plugins && typeof plugins === "object" && !Array.isArray(plugins)) {
        const roots = plugins.discoveryRoots;
        if (Array.isArray(roots)) {
            const out = roots.filter((x) => typeof x === "string" && x.trim().length > 0);
            if (out.length > 0)
                return out;
        }
    }
    return [".claude/plugins"];
}
function isDir(p) {
    try {
        return fs.statSync(p).isDirectory();
    }
    catch {
        return false;
    }
}
/**
 * Scan configured plugin roots for Claude-layout packages: `<root>/<plugin>/.claude-plugin/plugin.json`.
 */
export function discoverPluginPackages(workspacePath, effectiveConfig) {
    const roots = readDiscoveryRoots(effectiveConfig);
    const byName = new Map();
    for (const relRoot of roots) {
        const rootAbs = path.resolve(workspacePath, relRoot);
        if (!isDir(rootAbs)) {
            continue;
        }
        let entries;
        try {
            entries = fs.readdirSync(rootAbs, { withFileTypes: true });
        }
        catch {
            return { ok: false, code: "plugin-discovery-read-error", message: `Cannot read plugin root: ${relRoot}` };
        }
        for (const ent of entries) {
            if (!ent.isDirectory())
                continue;
            const dirName = ent.name;
            const dirAbs = path.join(rootAbs, dirName);
            const manifestAbs = path.join(dirAbs, ...MANIFEST_SEGMENTS);
            if (!fs.existsSync(manifestAbs)) {
                continue;
            }
            const rootRelativePath = path.relative(workspacePath, dirAbs).split(path.sep).join("/");
            const manifestPathRelative = path.join(rootRelativePath, ...MANIFEST_SEGMENTS).split(path.sep).join("/");
            let rawJson;
            try {
                rawJson = fs.readFileSync(manifestAbs, "utf8");
            }
            catch {
                return {
                    ok: false,
                    code: "plugin-read-error",
                    message: `Cannot read ${manifestPathRelative}`
                };
            }
            let parsed;
            try {
                parsed = JSON.parse(rawJson);
            }
            catch (e) {
                const rec = {
                    name: dirName,
                    version: null,
                    description: null,
                    rootPath: dirAbs,
                    rootRelativePath,
                    manifestPathRelative,
                    manifest: null,
                    manifestValid: false,
                    manifestErrors: [`invalid JSON: ${e.message}`],
                    pathDiagnostics: []
                };
                if (byName.has(rec.name)) {
                    return {
                        ok: false,
                        code: "plugin-duplicate-name",
                        message: `Duplicate plugin name '${rec.name}' across discovery roots`
                    };
                }
                byName.set(rec.name, rec);
                continue;
            }
            const v = validateClaudePluginManifestJson(parsed);
            if (!v.ok) {
                const rec = {
                    name: typeof parsed.name === "string" ? String(parsed.name) : dirName,
                    version: null,
                    description: null,
                    rootPath: dirAbs,
                    rootRelativePath,
                    manifestPathRelative,
                    manifest: null,
                    manifestValid: false,
                    manifestErrors: [v.message],
                    pathDiagnostics: v.pathDiagnostics
                };
                if (byName.has(rec.name)) {
                    return {
                        ok: false,
                        code: "plugin-duplicate-name",
                        message: `Duplicate plugin name '${rec.name}' across discovery roots`
                    };
                }
                byName.set(rec.name, rec);
                continue;
            }
            const m = v.manifest;
            if (byName.has(m.name)) {
                return {
                    ok: false,
                    code: "plugin-duplicate-name",
                    message: `Duplicate plugin name '${m.name}' across discovery roots`
                };
            }
            const rec = {
                name: m.name,
                version: m.version ?? null,
                description: m.description ?? null,
                rootPath: dirAbs,
                rootRelativePath,
                manifestPathRelative,
                manifest: m,
                manifestValid: true,
                manifestErrors: [],
                pathDiagnostics: []
            };
            byName.set(m.name, rec);
        }
    }
    const plugins = [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
    return { ok: true, plugins };
}
export function getPluginRecordByName(workspacePath, effectiveConfig, pluginName) {
    const res = discoverPluginPackages(workspacePath, effectiveConfig);
    if (!res.ok)
        return undefined;
    return res.plugins.find((p) => p.name === pluginName);
}
export function defaultManifestRelativePathForDocs() {
    return manifestRelPosix();
}
