import {} from '../channels/index.js';
import { logger } from '../utils/logger.js';
import { summarizeError } from '../utils/error-display.js';
/**
 * createPluginAPI — Factory that creates a sandboxed PluginAPI for a single plugin.
 * All registrations are tracked in `ctx.cleanup` so they can be undone on deactivation.
 */
export function createPluginAPI(ctx) {
    return {
        registerCommand(name, description, handler) {
            // Namespace commands to avoid collisions: "plugin-<pluginName>-<name>"
            const cmdName = `plugin-${ctx.pluginName}-${name}`;
            const cmd = {
                name: cmdName,
                description: `[${ctx.pluginName}] ${description}`,
                handler: async (args) => {
                    try {
                        await handler(args);
                    }
                    catch (err) {
                        logger.error(`[plugin:${ctx.pluginName}] Command '${name}' threw: ${summarizeError(err)}`);
                    }
                },
            };
            ctx.commandRegistry.register(cmd);
            ctx.cleanup.push(() => ctx.commandRegistry.unregister(cmdName));
        },
        async registerProvider(name, config) {
            // Dynamically import to avoid circular dependency at module load time.
            try {
                const { OpenAICompatProvider } = await import('../providers/openai-compat.js');
                try {
                    const provider = new OpenAICompatProvider({
                        name,
                        baseURL: config.baseURL,
                        apiKey: config.apiKey ?? '',
                        defaultModel: config.models[0] ?? '',
                        models: config.models,
                        ...(config.embeddingModel ? { embeddingModel: config.embeddingModel } : {}),
                        ...(config.reasoningFormat ? { reasoningFormat: config.reasoningFormat } : {}),
                        ...(config.authEnvVars ? { authEnvVars: config.authEnvVars } : {}),
                        ...(config.serviceNames ? { serviceNames: config.serviceNames } : {}),
                        ...(config.subscriptionProviderId ? { subscriptionProviderId: config.subscriptionProviderId } : {}),
                    });
                    const unregister = ctx.providerRegistry.registerRuntimeProvider({
                        provider,
                        models: config.models.map((modelId) => ({
                            id: modelId,
                            provider: name,
                            registryKey: `${name}:${modelId}`,
                            displayName: config.displayName ?? modelId,
                            description: `Plugin provider ${name}`,
                            contextWindow: config.contextWindow ?? 8192,
                            selectable: true,
                            capabilities: {
                                toolCalling: config.capabilities?.toolCalling ?? true,
                                codeEditing: config.capabilities?.codeEditing ?? true,
                                reasoning: config.capabilities?.reasoning ?? false,
                                multimodal: config.capabilities?.multimodal ?? false,
                            },
                            ...(config.reasoningEffort ? { reasoningEffort: config.reasoningEffort } : {}),
                            ...(config.tier ? { tier: config.tier } : {}),
                            ...(config.tokenLimits ? { tokenLimits: config.tokenLimits } : {}),
                        })),
                        suppressCatalogModelRegistryKeys: config.suppressCatalogModelRegistryKeys,
                    });
                    ctx.cleanup.push(unregister);
                    logger.info(`[plugin:${ctx.pluginName}] Registered provider '${name}' with ${config.models.length} model(s)`);
                }
                catch (err) {
                    logger.error(`[plugin:${ctx.pluginName}] registerProvider '${name}' failed: ${summarizeError(err)}`);
                    throw err;
                }
            }
            catch (err) {
                logger.error(`[plugin:${ctx.pluginName}] Could not import OpenAICompatProvider: ${summarizeError(err)}`);
                throw err;
            }
        },
        registerProviderInstance(registration) {
            const unregister = ctx.providerRegistry.registerRuntimeProvider({
                provider: registration.provider,
                models: (registration.models ?? []).map((model) => ({
                    id: model.id,
                    provider: registration.provider.name,
                    registryKey: `${registration.provider.name}:${model.id}`,
                    displayName: model.displayName ?? model.id,
                    description: model.description ?? `Plugin provider ${registration.provider.name}`,
                    contextWindow: model.contextWindow ?? 8192,
                    selectable: model.selectable ?? true,
                    capabilities: {
                        toolCalling: model.capabilities?.toolCalling ?? true,
                        codeEditing: model.capabilities?.codeEditing ?? true,
                        reasoning: model.capabilities?.reasoning ?? false,
                        multimodal: model.capabilities?.multimodal ?? false,
                    },
                    ...(model.reasoningEffort ? { reasoningEffort: model.reasoningEffort } : {}),
                    ...(model.tier ? { tier: model.tier } : {}),
                    ...(model.tokenLimits ? { tokenLimits: model.tokenLimits } : {}),
                })),
                suppressCatalogModelRegistryKeys: registration.suppressCatalogModelRegistryKeys,
                replace: registration.replace,
            });
            ctx.cleanup.push(unregister);
            logger.info(`[plugin:${ctx.pluginName}] Registered provider instance '${registration.provider.name}'`);
        },
        registerTool(name, schema, handler) {
            const toolName = `plugin_${ctx.pluginName}_${name}`;
            if (ctx.toolRegistry.has(toolName)) {
                logger.warn(`[plugin:${ctx.pluginName}] Tool '${toolName}' already registered — skipping`);
                return;
            }
            const definition = {
                name: toolName,
                description: schema.description ?? `Plugin tool: ${name}`,
                parameters: schema,
            };
            ctx.toolRegistry.register({
                definition,
                execute: async (args) => {
                    try {
                        return await handler(args);
                    }
                    catch (err) {
                        return { success: false, error: summarizeError(err) };
                    }
                },
            });
            // ToolRegistry has no unregister method. Track for cleanup awareness.
            ctx.cleanup.push(() => {
                logger.warn(`[plugin:${ctx.pluginName}] Tool '${toolName}' cannot be unregistered on deactivate — it persists until process restart`);
            });
        },
        registerGatewayMethod(descriptor, handler) {
            const methodId = descriptor.id.startsWith(`plugin.${ctx.pluginName}.`)
                ? descriptor.id
                : `plugin.${ctx.pluginName}.${descriptor.id}`;
            const unregister = ctx.gatewayMethods.register({
                ...descriptor,
                id: methodId,
                source: 'plugin',
                pluginId: ctx.pluginName,
            }, handler);
            ctx.cleanup.push(unregister);
            logger.info(`[plugin:${ctx.pluginName}] Registered gateway method '${methodId}'`);
        },
        registerChannelPlugin(plugin) {
            const registry = ctx.channelRegistry;
            registry.register(plugin);
            ctx.cleanup.push(() => {
                if (registry.get(plugin.id) === plugin)
                    registry.unregister(plugin.id);
            });
            logger.info(`[plugin:${ctx.pluginName}] Registered channel plugin '${plugin.id}'`);
        },
        registerDeliveryStrategy(strategy, options = {}) {
            const router = ctx.channelDeliveryRouter;
            router.registerStrategy(strategy, options);
            ctx.cleanup.push(() => {
                router.unregisterStrategy(strategy.id);
            });
            logger.info(`[plugin:${ctx.pluginName}] Registered delivery strategy '${strategy.id}'`);
        },
        registerMemoryEmbeddingProvider(provider, options = {}) {
            const unregister = ctx.memoryEmbeddingRegistry.register(provider, options);
            ctx.cleanup.push(unregister);
            logger.info(`[plugin:${ctx.pluginName}] Registered memory embedding provider '${provider.id}'`);
        },
        registerVoiceProvider(provider, options = {}) {
            const unregister = ctx.voiceProviderRegistry.register(provider, options);
            ctx.cleanup.push(unregister);
            logger.info(`[plugin:${ctx.pluginName}] Registered voice provider '${provider.id}'`);
        },
        registerMediaProvider(provider, options = {}) {
            const unregister = ctx.mediaProviderRegistry.register(provider, options);
            ctx.cleanup.push(unregister);
            logger.info(`[plugin:${ctx.pluginName}] Registered media provider '${provider.id}'`);
        },
        registerWebSearchProvider(provider, options = {}) {
            const unregister = ctx.webSearchProviderRegistry.register(provider, options);
            ctx.cleanup.push(unregister);
            logger.info(`[plugin:${ctx.pluginName}] Registered web search provider '${provider.id}'`);
        },
        onEvent(eventName, handler) {
            const unsub = ctx.runtimeBus.on(eventName, (envelope) => handler(envelope.payload));
            ctx.cleanup.push(unsub);
            return unsub;
        },
        getConfig(key) {
            return ctx.pluginConfig[key];
        },
        log(level, message) {
            logger[level](`[plugin:${ctx.pluginName}] ${message}`);
        },
    };
}
