import { z } from "zod";
/**
 * Plugins with deprecated parameter aliases declare two schemas: a canonical
 * one (new names only, with `.meta({ aliases })` declarations) and a union
 * of the canonical + a deprecated variant for runtime input parsing. The
 * union form is what `createPluginMethod` stores in plugin meta so SDK
 * callers passing deprecated names keep validating; for the registry — and
 * all downstream consumers (CLI help, MCP tool definitions, generated
 * docs) — we want only the canonical.
 *
 * Convention: when a plugin's `inputSchema` is a `z.ZodUnion`, the first
 * variant is the canonical schema. Every plugin that uses unions today
 * follows this; explicit, easy to enforce, no extra metadata needed.
 */
function canonicalInputSchema(schema) {
    if (schema instanceof z.ZodUnion) {
        return schema.options[0];
    }
    return schema;
}
const categoryDefinitions = {
    account: { title: "Account" },
    app: { title: "App", titlePlural: "Apps" },
    connection: { title: "Connection" },
    action: { title: "Action" },
    "client-credentials": {
        title: "Client Credentials",
        titlePlural: "Client Credentials",
    },
    table: { title: "Table" },
    trigger: { title: "Trigger" },
    http: { title: "HTTP Request" },
    utility: { title: "Utility", titlePlural: "Utilities" },
    other: { title: "Other" },
};
const knownCategories = Object.keys(categoryDefinitions);
export function buildRegistry({ sdk, meta, packageFilter, }) {
    const functions = Object.keys(meta)
        .filter((key) => {
        const property = sdk[key];
        if (typeof property === "function")
            return true;
        const [rootKey] = key.split(".");
        const rootProperty = sdk[rootKey];
        return typeof rootProperty === "object" && rootProperty !== null;
    })
        .map((key) => {
        const m = meta[key];
        return {
            name: key,
            description: m.description,
            type: m.type,
            itemType: m.itemType,
            returnType: m.returnType,
            inputSchema: canonicalInputSchema(m.inputSchema),
            inputParameters: m.inputParameters,
            outputSchema: m.outputSchema,
            categories: m.categories || [],
            resolvers: m.resolvers,
            formatter: m.formatter,
            experimental: m.experimental,
            packages: m.packages,
            confirm: m.confirm ?? (m.type === "delete" ? "delete" : undefined),
            deprecation: m.deprecation,
            aliases: m.aliases,
            supportsJsonOutput: m.supportsJsonOutput ?? true,
        };
    })
        .sort((a, b) => a.name.localeCompare(b.name));
    const filteredFunctions = packageFilter
        ? functions.filter((f) => !f.packages || f.packages.includes(packageFilter))
        : functions;
    const filteredCategories = knownCategories
        .slice()
        .sort((a, b) => {
        if (a === "other")
            return 1;
        if (b === "other")
            return -1;
        return categoryDefinitions[a].title.localeCompare(categoryDefinitions[b].title);
    })
        .map((categoryKey) => {
        const categoryFunctions = filteredFunctions
            .filter((f) => f.categories.includes(categoryKey) ||
            (categoryKey === "other" &&
                !f.categories.some((c) => knownCategories.includes(c))))
            .map((f) => f.name)
            .sort();
        const definition = categoryDefinitions[categoryKey];
        return {
            key: categoryKey,
            title: definition.title,
            titlePlural: definition.titlePlural ?? `${definition.title}s`,
            functions: categoryFunctions,
        };
    })
        .filter((category) => category.functions.length > 0);
    return { functions: filteredFunctions, categories: filteredCategories };
}
