import { CHANNEL_COMMANDS } from "./channel-command-catalog.js";
import { normalizeChannelCommandName } from "./channel-runtime.js";
export function createSharedChannelCommandDispatcher(input) {
    const handlers = new Map();
    for (const binding of input.bindings) {
        for (const name of binding.names) {
            const normalized = normalizeChannelCommandName(name);
            if (!normalized) {
                throw new Error("Channel command name is required.");
            }
            if (handlers.has(normalized)) {
                throw new Error(`Duplicate ${input.transport} command binding: ${normalized}`);
            }
            handlers.set(normalized, binding.handler);
        }
    }
    return {
        transport: input.transport,
        commandNames: [...handlers.keys()].sort(),
        async dispatch(request, command, argument) {
            const normalized = normalizeChannelCommandName(command);
            const handler = handlers.get(normalized);
            if (!handler) {
                return { matched: false, command: normalized };
            }
            await handler(request, argument, normalized);
            return { matched: true, command: normalized };
        },
    };
}
export function channelCatalogCommandNames(transport) {
    return CHANNEL_COMMANDS
        .filter((entry) => {
        if (transport === "telegram")
            return entry.telegram !== false;
        if (transport === "discord")
            return entry.discord !== false;
        if (transport === "slack")
            return entry.slack !== false;
        return entry.matrix !== false;
    })
        .map((entry) => normalizeChannelCommandName(entry.name))
        .sort();
}
export function channelCommandCoverage(input) {
    const advertised = new Set(channelCatalogCommandNames(input.transport));
    const implemented = new Set([...input.implemented].map(normalizeChannelCommandName));
    for (const [canonical, aliases] of Object.entries(input.aliases ?? {})) {
        if (!implemented.has(normalizeChannelCommandName(canonical)))
            continue;
        for (const alias of aliases) {
            implemented.add(normalizeChannelCommandName(alias));
        }
    }
    const aliasNames = new Set(Object.values(input.aliases ?? {}).flat().map(normalizeChannelCommandName));
    return {
        advertised: [...advertised].sort(),
        implemented: [...implemented].sort(),
        missing: [...advertised].filter((name) => !implemented.has(name)).sort(),
        extra: [...implemented].filter((name) => !advertised.has(name) && !aliasNames.has(name)).sort(),
    };
}
