/**
 * Unified Command System - Core Types
 *
 * Provides a platform-agnostic command system that works across
 * Telegram, Feishu, Web UI, CLI, and other channel surfaces.
 */
import type { Config } from '../config/schema.js';
import type { PersistentGoalApis } from '../agent/goals/persistent-goal-apis.js';
import type { AgentMessage } from '@earendil-works/pi-agent-core';
import type { ThinkLevel, ReasoningLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';
import type { SessionConfigStore } from '../session/index.js';
export type MessageSource = 'telegram' | 'weixin' | 'feishu' | 'webui' | 'cli' | 'api' | 'system' | 'gateway';
export interface UnifiedMessage {
    /** Message source platform */
    source: MessageSource;
    /** Channel identifier (e.g., 'telegram:default') */
    channelId: string;
    /** Platform-specific chat ID */
    chatId: string;
    /** Sender's platform-specific ID */
    senderId: string;
    /** Sender's display name */
    senderName?: string;
    /** Message content text */
    content: string;
    /** Whether this is a command (starts with / or :) */
    isCommand: boolean;
    /** Command name without prefix (e.g., 'new', 'usage') */
    commandName?: string;
    /** Command arguments */
    commandArgs?: string;
    /** Unified session key */
    sessionKey: string;
    /** Platform-specific metadata */
    platformData: PlatformMetadata;
    /** Optional attachments */
    attachments?: MessageAttachment[];
    /** Message timestamp */
    timestamp: number;
}
export interface PlatformMetadata {
    /** Platform message ID */
    messageId?: string;
    /** Thread/topic ID for forum-style chats */
    threadId?: string;
    /** Whether this is a group chat */
    isGroup: boolean;
    /** Whether this is a forum/topic */
    isForum?: boolean;
    /** Bot username (for mention detection) */
    botUsername?: string;
    /** Account ID for multi-account channels */
    accountId?: string;
    /** Raw platform-specific data (adapter use only) */
    raw?: unknown;
}
export interface MessageAttachment {
    type: 'photo' | 'video' | 'audio' | 'voice' | 'document' | 'sticker';
    mimeType?: string;
    data?: string;
    url?: string;
    name?: string;
    size?: number;
    /** For voice messages: transcribed text */
    transcribedText?: string;
}
export type CommandCategory = 'session' | 'model' | 'system' | 'tool' | 'extension';
export type CommandScope = 'global' | 'private' | 'group';
export interface CommandDefinition {
    /** Unique command identifier */
    id: string;
    /** Command name (without / prefix) */
    name: string;
    /** Alternative names/aliases */
    aliases?: string[];
    /** Human-readable description */
    description: string;
    /** Command category */
    category: CommandCategory;
    /** Where this command can be used */
    scope: CommandScope[];
    /** Whether command accepts arguments */
    acceptsArgs?: boolean;
    /** Example usage */
    examples?: string[];
    /** Handler function */
    handler: CommandHandler;
}
export type CommandHandler = (context: CommandContext, args: string) => Promise<CommandResult | void>;
export interface CompactSessionResult {
    compacted: boolean;
    tokensBefore: number;
    tokensAfter: number;
    summary?: string;
}
export interface CommandResult {
    /** Response text */
    content: string;
    /** Whether command succeeded */
    success?: boolean;
    /** Optional UI components */
    components?: UIComponent[];
    /** Additional metadata */
    metadata?: Record<string, unknown>;
}
export interface CommandContext {
    /** Unified session key */
    sessionKey: string;
    /** Message source platform */
    source: MessageSource;
    /** Channel ID */
    channelId: string;
    /** Chat ID */
    chatId: string;
    /** Sender ID */
    senderId: string;
    /** Whether this is a group context */
    isGroup: boolean;
    /** Bot configuration */
    config: Config;
    /** Send a text reply */
    reply(text: string, options?: ReplyOptions): Promise<void>;
    /** Send a UI component */
    replyComponent(component: UIComponent): Promise<void>;
    /** Show typing indicator */
    setTyping(typing: boolean): Promise<void>;
    /** Get current session messages */
    getSession(): Promise<AgentMessage[]>;
    /** Clear current session (start fresh) */
    clearSession(): Promise<void>;
    /** Reset session in place (archive transcript, new session id; preserve overrides) */
    resetSession(): Promise<void>;
    /** Archive current session */
    archiveSession(): Promise<void>;
    /** List user's sessions */
    listSessions(): Promise<SessionInfo[]>;
    /** Switch to a different session */
    switchSession(sessionKey: string): Promise<void>;
    /** Get current model ID */
    getCurrentModel(): string;
    /** List available models */
    listModels(): Promise<ModelInfo[]>;
    /** Switch to a different model */
    switchModel(modelId: string): Promise<boolean>;
    /** Get token usage stats */
    getUsage(): Promise<UsageStats>;
    /** Check if platform supports a feature */
    supports(feature: PlatformFeature): boolean;
    /** Get current configuration */
    getConfig?(): Config;
    /** Update configuration value */
    updateConfig?(path: string, value: unknown): Promise<boolean>;
    /** Persist session thinking level and sync in-memory agent (when wired) */
    setThinkingLevel?(level: ThinkLevel): Promise<void>;
    /**
     * Update pi-agent thinking level in memory only (used with runtime config overrides so session
     * store does not mask merged defaults).
     */
    syncAgentThinkingLevel?(level: ThinkLevel): void;
    getSessionConfigStore?(): SessionConfigStore | undefined;
    getThinkingLevel?(): Promise<ThinkLevel | undefined>;
    getReasoningLevel?(): Promise<ReasoningLevel | undefined>;
    getVerboseLevel?(): Promise<VerboseLevel | undefined>;
    /** Summarize older turns into a memory line; optional focus text for the summarizer. */
    compactSession?(options?: {
        instructions?: string;
        force?: boolean;
    }): Promise<CompactSessionResult | null>;
    /** Side question: LLM answer without appending to the session transcript. */
    btwQuery?(question: string): Promise<{
        text: string;
        error?: string;
    }>;
    /** Write session transcript to workspace `exports/` (markdown, html, or json). */
    exportSessionToWorkspace?(format: 'markdown' | 'html' | 'json'): Promise<{
        path: string;
    }>;
    /** Debug view: config + transcript stats (`list` | `detail` | `json`). */
    agentContextReport?(mode?: 'list' | 'detail' | 'json'): Promise<string>;
    /** Abort in-flight assistant generation and channel streaming for this session (e.g. /abort) */
    abortCurrentTurn?(): Promise<void>;
    /** Session store + continuation scheduling for built-in persistent `/goal` (when wired). */
    persistentGoalApis?: PersistentGoalApis;
}
export type PlatformFeature = 'buttons' | 'markdown' | 'html' | 'threads' | 'reactions' | 'edit' | 'delete' | 'typing' | 'voice';
export interface ReplyOptions {
    /** Parse mode */
    parseMode?: 'markdown' | 'html' | 'plain';
    /** Reply to message ID */
    replyTo?: string;
    /** Whether to show notification */
    silent?: boolean;
    /** Attach UI components */
    components?: UIComponent[];
}
export type UIComponent = ButtonGroup | SelectMenu | ModelPicker | UsageDisplay | SessionList | TextInput;
export interface ButtonGroup {
    type: 'buttons';
    buttons: Array<{
        id: string;
        text: string;
        style?: 'primary' | 'secondary' | 'danger';
    }>;
    layout?: 'horizontal' | 'vertical';
}
export interface SelectMenu {
    type: 'select';
    placeholder?: string;
    options: Array<{
        value: string;
        label: string;
        description?: string;
    }>;
}
export interface ModelPicker {
    type: 'model-picker';
    providers: ProviderInfo[];
    currentModel?: string;
}
export interface UsageDisplay {
    type: 'usage-display';
    stats: UsageStats;
    modelName: string;
}
export interface SessionList {
    type: 'session-list';
    sessions: SessionInfo[];
    currentSession: string;
}
export interface TextInput {
    type: 'text-input';
    placeholder?: string;
    multiline?: boolean;
}
export interface ProviderInfo {
    id: string;
    name: string;
    icon?: string;
    models: ModelInfo[];
}
export interface ModelInfo {
    id: string;
    name: string;
    provider: string;
    description?: string;
    contextWindow?: number;
}
export interface UsageStats {
    promptTokens: number;
    completionTokens: number;
    totalTokens: number;
    messageCount: number;
}
export interface SessionInfo {
    key: string;
    name?: string;
    messageCount: number;
    createdAt: Date;
    updatedAt: Date;
    isActive: boolean;
}
export interface ChannelAdapter {
    /** Adapter identifier */
    readonly id: MessageSource;
    /** Adapter display name */
    readonly name: string;
    /** Supported features */
    readonly features: PlatformFeature[];
    /** Initialize adapter */
    init(config: Config): Promise<void>;
    /** Start receiving messages */
    start(): Promise<void>;
    /** Stop receiving messages */
    stop(): Promise<void>;
    /** Convert platform message to unified format */
    normalizeMessage(platformMsg: unknown): Promise<UnifiedMessage | null>;
    /** Send a reply */
    sendReply(chatId: string, reply: ReplyPayload): Promise<void>;
    /** Set typing indicator */
    setTyping(chatId: string, typing: boolean): Promise<void>;
}
export interface ReplyPayload {
    text: string;
    parseMode?: 'markdown' | 'html' | 'plain';
    components?: UIComponent[];
    replyTo?: string;
    silent?: boolean;
}
export interface CommandRegistry {
    /** Register a command */
    register(command: CommandDefinition): void;
    /** Unregister a command */
    unregister(commandId: string): void;
    /** Get command by name */
    get(name: string): CommandDefinition | undefined;
    /** Get all commands */
    list(): CommandDefinition[];
    /** Get commands by category */
    listByCategory(category: CommandCategory): CommandDefinition[];
    /** Check if command exists */
    has(name: string): boolean;
    /** Execute a command */
    execute(name: string, context: CommandContext, args: string): Promise<CommandResult>;
}
