/**
 * Extension System - Core Types
 *
 * Core extension definitions and Extension API interface.
 */
import type { Command } from 'commander';
import type { Config } from '../../config/config-surface.js';
import type { Config as FullConfig } from '../../config/schema.js';
import type { MessageBus } from '../../infra/bus/index.js';
import type { TypedEventBus } from './events.js';
import type { AgentTool } from '@earendil-works/pi-agent-core';
import type { ExtensionHookEvent, ExtensionHookHandler, HookOptions, HookHandlerMap } from './hooks.js';
import type { ChannelPlugin } from '../../channels/plugin-types.js';
import type { SessionMetadata } from '../../session/types.js';
import type { FlagConfig, FlagValue, ShortcutConfig } from './phase4.js';
import type { ProviderPlugin } from './providers.js';
import type { TuiExtensionRegistrar } from './tui.js';
export interface ExtensionDefinition {
    /** Unique extension identifier */
    id: string;
    /** Human-readable name */
    name: string;
    /** Extension description */
    description?: string;
    /** Extension version */
    version?: string;
    /** Extension kind */
    kind?: ExtensionKind;
    /** Configuration schema (JSON Schema) */
    configSchema?: Record<string, unknown>;
    /** Register hook - called when extension is registered */
    register?: (api: ExtensionApi) => void | Promise<void>;
    /** Activate hook - called when extension is enabled */
    activate?: (api: ExtensionApi) => void | Promise<void>;
    /** Deactivate hook - called when extension is disabled */
    deactivate?: (api: ExtensionApi) => void | Promise<void>;
}
export type ExtensionKind = 'channel' | 'provider' | 'memory' | 'tool' | 'utility' | 'tts' | 'speech-provider' | 'media-provider' | 'image-generation' | 'web-search';
export type ExtensionModule = ExtensionDefinition | ((api: ExtensionApi) => void | Promise<void>);
/** Optional: session manager when extension runs inside Gateway. */
export type ExtensionSessionManager = {
    initialize?: () => Promise<void>;
    getSessionMetadata?: (key: string) => Promise<SessionMetadata | null>;
    updateSessionMetadata?: (key: string, updates: Partial<SessionMetadata>) => Promise<void>;
};
export interface ExtensionRuntime {
    config: Config;
    /** Present when ExtensionLoader.setRuntimeContext was used (e.g. Gateway). */
    bus?: MessageBus;
    log: ExtensionLogger;
    sessionManager?: ExtensionSessionManager;
    /**
     * Queue another webchat agent turn (same as POST /api/agent) after the current run unlocks.
     * Only injected in the Gateway process.
     */
    scheduleWebchatContinuation?: (sessionKey: string, message: string) => void;
}
export interface ExtensionCliRegistration {
    extensionId: string;
    commands: string[];
    factory: (ctx: {
        program: Command;
    }) => void;
}
export interface ExtensionApi {
    /** Extension ID */
    readonly id: string;
    /** Extension name */
    readonly name: string;
    /** Extension version */
    readonly version?: string;
    /** Extension source path */
    readonly source: string;
    /** Runtime configuration */
    readonly config: Config;
    /** Extension-specific configuration */
    readonly extensionConfig: Record<string, unknown>;
    /** Logger instance */
    readonly logger: ExtensionLogger;
    registerTool(tool: AgentTool): void;
    registerHook(event: ExtensionHookEvent, handler: ExtensionHookHandler, opts?: HookOptions): void;
    onHook<K extends ExtensionHookEvent>(hookName: K, handler: HookHandlerMap[K], opts?: {
        priority?: number;
    }): void;
    /** Register a channel plugin (object form). */
    registerChannel(registration: {
        plugin: ChannelPlugin;
    }): void;
    registerHttpRoute(path: string, handler: HttpRequestHandler): void;
    registerCommand(command: ExtensionCommand): void;
    /**
     * Bind a handler to a manifest-declared command id (`ui.contributions.commands`).
     * Metadata comes from the manifest; optional `chatAlias` becomes the slash command name.
     */
    onCommand(commandId: string, handler: ExtensionCommandHandler): void;
    /**
     * Register a reload handler when config paths matching this extension change during hot reload.
     */
    registerReload(handler: ExtensionReloadHandler): void;
    registerService(service: ExtensionService): void;
    registerGatewayMethod(method: string, handler: GatewayMethodHandler): void;
    /**
     * Register Commander subcommands. Apply with
     * `registerExtensionCliProgram(program, registry)` when wiring CLI.
     */
    registerCli(factory: (ctx: {
        program: Command;
    }) => void, opts?: {
        commands: string[];
    }): void;
    /** Gateway-injected runtime (bus, full config, session). Only set when ExtensionLoader.setRuntimeContext was used. */
    readonly runtime: ExtensionRuntime;
    resolvePath(input: string): string;
    emit(event: string, data: unknown): void;
    on(event: string, handler: (data: unknown) => void): void;
    off(event: string, handler: (data: unknown) => void): void;
    events: TypedEventBus;
    registerProvider(plugin: ProviderPlugin): void;
    registerProviderPlugin(plugin: ProviderPlugin): void;
    /** Register a speech (TTS) provider plugin. */
    registerSpeechProvider(plugin: import('../../voice/tts/speech-provider-types.js').SpeechProviderPlugin): void;
    /** Register a media understanding (STT / image / video) provider plugin. */
    registerMediaUnderstandingProvider(plugin: import('../../media-understanding/types.js').MediaUnderstandingProvider): void;
    /**
     * Register a skills marketplace adapter (e.g. a third-party skill catalog).
     * The adapter will appear in the UI provider picker and can be selected by users.
     */
    registerMarketplaceAdapter(registration: {
        adapter: import('../../agent/skills/marketplace/adapter.types.js').SkillsMarketplaceAdapter;
        displayName?: string;
    }): void;
    registerFlag(name: string, config: FlagConfig, extensionId?: string): void;
    getFlag(name: string): FlagValue;
    registerShortcut(key: string, config: ShortcutConfig): void;
    /**
     * Register TUI contributions (footer/header widgets, autocomplete, tool renderers).
     * Callback runs when `xopc tui` starts — not during gateway-only extension load.
     */
    registerTui(register: TuiExtensionRegistrar): void;
}
export interface ExtensionLogger {
    debug(msg: string): void;
    info(msg: string): void;
    warn(msg: string): void;
    error(msg: string): void;
}
export interface HttpRequest {
    method: string;
    url: string;
    headers: Record<string, string>;
    body?: unknown;
}
export interface HttpResponse {
    status: number;
    headers?: Record<string, string>;
    body?: unknown;
}
export type HttpRequestHandler = (req: HttpRequest) => HttpResponse | Promise<HttpResponse>;
export type GatewayMethodHandler = (params: unknown) => unknown | Promise<unknown>;
export interface ExtensionReloadResult {
    success: boolean;
    error?: string;
}
export type ExtensionReloadHandler = (newConfig: FullConfig, changedPaths: string[]) => ExtensionReloadResult | Promise<ExtensionReloadResult>;
export interface ExtensionReloadRegistration {
    extensionId: string;
    handler: ExtensionReloadHandler;
    /** Config path prefixes this handler cares about. Empty = any extension-related change passed to matcher. */
    configPrefixes: string[];
}
/**
 * Chat command registered by an extension (bridged into CommandRegistry with category `extension`).
 */
export interface ExtensionCommand {
    name: string;
    description: string;
    aliases?: string[];
    scope?: Array<'global' | 'private' | 'group'>;
    acceptsArgs?: boolean;
    examples?: string[];
    handler: ExtensionCommandHandler;
}
export type ExtensionCommandHandler = (args: string, context: ExtensionCommandContext) => Promise<ExtensionCommandResult | void> | ExtensionCommandResult | void;
export interface ExtensionCommandContext {
    sessionKey: string;
    source: string;
    isGroup: boolean;
    config: Config;
    reply(text: string): Promise<void>;
}
export interface ExtensionCommandResult {
    content: string;
    success?: boolean;
}
export interface ExtensionService {
    id: string;
    name: string;
    start?: () => void | Promise<void>;
    stop?: () => void | Promise<void>;
}
export interface ExtensionRegistry {
    addTool(tool: AgentTool): void;
    getTools(): Map<string, AgentTool>;
    getTool(name: string): AgentTool | undefined;
    getAllTools(): AgentTool[];
    getCommand(name: string): ExtensionCommand | undefined;
    addCliRegistration(reg: ExtensionCliRegistration): void;
    getCliRegistrations(): readonly ExtensionCliRegistration[];
}
