/**
 * Multi-Channel Support
 *
 * Inspired by OpenClaw's multi-platform messaging support.
 * Provides unified interface for Telegram, Discord, Slack, and more.
 */
import { EventEmitter } from 'events';
import type { CanonicalIdentity } from './identity-links.js';
/**
 * Supported channel types
 */
export type ChannelType = 'telegram' | 'discord' | 'slack' | 'whatsapp' | 'signal' | 'matrix' | 'cli' | 'web' | 'api';
/**
 * Message direction
 */
export type MessageDirection = 'inbound' | 'outbound';
/**
 * Message content type
 */
export type ContentType = 'text' | 'image' | 'audio' | 'video' | 'file' | 'location' | 'contact' | 'sticker' | 'voice' | 'command';
/**
 * User/sender information
 */
export interface ChannelUser {
    /** User ID on the channel */
    id: string;
    /** Username or handle */
    username?: string;
    /** Display name */
    displayName?: string;
    /** Profile picture URL */
    avatarUrl?: string;
    /** Is this a bot */
    isBot?: boolean;
    /** Is this the channel owner/admin */
    isAdmin?: boolean;
    /** Raw platform-specific data */
    raw?: unknown;
}
/**
 * Channel/chat information
 */
export interface ChannelInfo {
    /** Channel ID */
    id: string;
    /** Channel type */
    type: ChannelType;
    /** Channel name */
    name?: string;
    /** Is this a direct message */
    isDM?: boolean;
    /** Is this a group chat */
    isGroup?: boolean;
    /** Number of participants */
    participantCount?: number;
    /** Channel description */
    description?: string;
    /** Raw platform-specific data */
    raw?: unknown;
}
/**
 * Attachment in a message
 */
export interface MessageAttachment {
    /** Attachment type */
    type: ContentType;
    /** URL to the attachment */
    url?: string;
    /** Local file path */
    filePath?: string;
    /** Base64 encoded data */
    data?: string;
    /** MIME type */
    mimeType?: string;
    /** File name */
    fileName?: string;
    /** File size in bytes */
    size?: number;
    /** Duration for audio/video */
    duration?: number;
    /** Dimensions for images/videos */
    width?: number;
    height?: number;
    /** Caption */
    caption?: string;
}
/**
 * Incoming message
 */
export interface InboundMessage {
    /** Message ID */
    id: string;
    /** Channel info */
    channel: ChannelInfo;
    /** Sender info */
    sender: ChannelUser;
    /** Message content */
    content: string;
    /** Content type */
    contentType: ContentType;
    /** Attachments */
    attachments?: MessageAttachment[];
    /** Reply to message ID */
    replyTo?: string;
    /** Timestamp */
    timestamp: Date;
    /** Is this a command (starts with /) */
    isCommand?: boolean;
    /** Command name if isCommand */
    commandName?: string;
    /** Command arguments if isCommand */
    commandArgs?: string[];
    /** Thread/topic ID */
    threadId?: string;
    /** Session isolation key (computed by SessionIsolator) */
    sessionKey?: string;
    /** Raw platform message */
    raw?: unknown;
}
/**
 * Outgoing message
 */
export interface OutboundMessage {
    /** Target channel */
    channelId: string;
    /** Message content */
    content: string;
    /** Content type */
    contentType?: ContentType;
    /** Attachments */
    attachments?: MessageAttachment[];
    /** Reply to message ID */
    replyTo?: string;
    /** Thread/topic ID */
    threadId?: string;
    /** Parse mode (markdown, html, plain) */
    parseMode?: 'markdown' | 'html' | 'plain';
    /** Disable link preview */
    disablePreview?: boolean;
    /** Silent message (no notification) */
    silent?: boolean;
    /** Buttons/keyboard */
    buttons?: MessageButton[];
}
/**
 * Interactive button
 */
export interface MessageButton {
    /** Button text */
    text: string;
    /** Button type */
    type: 'url' | 'callback' | 'reply';
    /** URL for url type */
    url?: string;
    /** Callback data */
    data?: string;
}
/**
 * Message delivery result
 */
export interface DeliveryResult {
    /** Success flag */
    success: boolean;
    /** Sent message ID */
    messageId?: string;
    /** Error message if failed */
    error?: string;
    /** Timestamp */
    timestamp: Date;
}
/**
 * Channel status
 */
export interface ChannelStatus {
    /** Channel type */
    type: ChannelType;
    /** Is connected */
    connected: boolean;
    /** Is authenticated */
    authenticated: boolean;
    /** Last activity time */
    lastActivity?: Date;
    /** Error if any */
    error?: string;
    /** Additional info */
    info?: Record<string, unknown>;
}
/**
 * Channel configuration
 */
export interface ChannelConfig {
    /** Channel type */
    type: ChannelType;
    /** Is enabled */
    enabled: boolean;
    /** API token/key */
    token?: string;
    /** Webhook URL */
    webhookUrl?: string;
    /** Allowed users (for security) */
    allowedUsers?: string[];
    /** Allowed channels */
    allowedChannels?: string[];
    /** Auto-reply enabled */
    autoReply?: boolean;
    /** Rate limit (messages per minute) */
    rateLimit?: number;
    /** Custom options */
    options?: Record<string, unknown>;
}
/**
 * Channel events
 */
export interface ChannelEvents {
    'message': (message: InboundMessage) => void;
    'command': (message: InboundMessage) => void;
    'connected': (channel: ChannelType) => void;
    'disconnected': (channel: ChannelType, error?: Error) => void;
    'error': (channel: ChannelType, error: Error) => void;
    'typing': (channel: ChannelInfo, user: ChannelUser) => void;
    'reaction': (channel: ChannelInfo, messageId: string, emoji: string, user: ChannelUser) => void;
}
/**
 * Generate a session key for an inbound message using the SessionIsolator.
 *
 * This is a convenience function that uses the singleton SessionIsolator
 * to compute a session key from the message's channel and sender info.
 * Returns undefined if session isolation is not available.
 *
 * @param message - The inbound message to generate a key for
 * @param accountId - Optional bot account ID for multi-account setups
 * @returns The session key string, or undefined if isolation fails
 */
export declare function getSessionKey(message: InboundMessage, accountId?: string): string | undefined;
/**
 * Resolve the canonical identity for an inbound message's sender.
 *
 * Uses the singleton IdentityLinker to look up cross-channel identity links.
 * Returns null if no canonical identity exists for the sender.
 *
 * @param message - The inbound message whose sender to resolve
 * @returns The canonical identity, or null if no link exists
 */
export declare function getCanonicalIdentity(message: InboundMessage): CanonicalIdentity | null;
import type { ResolvedRoute, RouteAgentConfig } from './peer-routing.js';
/**
 * Resolve the best route for an inbound message using the singleton PeerRouter.
 *
 * This is a convenience function similar to `getSessionKey()` and
 * `checkDMPairing()`. It delegates to the singleton PeerRouter and
 * returns the resolved route (or null if no route matches).
 *
 * @param message - The inbound message to resolve a route for
 * @param accountId - Optional bot account ID for multi-account setups
 * @returns The resolved route with agent config, or null if no route matches
 */
export declare function resolveRoute(message: InboundMessage, accountId?: string): ResolvedRoute | null;
/**
 * Get the effective agent configuration for an inbound message.
 *
 * Resolves the route and merges the matched agent config with defaults.
 * Always returns a config object (falls back to default if no route matches).
 *
 * @param message - The inbound message to get config for
 * @param accountId - Optional bot account ID for multi-account setups
 * @returns The effective agent configuration
 */
export declare function getRouteAgentConfig(message: InboundMessage, accountId?: string): RouteAgentConfig;
/**
 * Abstract base class for channel implementations
 */
export declare abstract class BaseChannel extends EventEmitter {
    readonly type: ChannelType;
    protected config: ChannelConfig;
    protected status: ChannelStatus;
    constructor(type: ChannelType, config: ChannelConfig);
    /**
     * Connect to the channel
     */
    abstract connect(): Promise<void>;
    /**
     * Disconnect from the channel
     */
    abstract disconnect(): Promise<void>;
    /**
     * Send a message
     */
    abstract send(message: OutboundMessage): Promise<DeliveryResult>;
    /**
     * Get channel status
     */
    getStatus(): ChannelStatus;
    /**
     * Check if user is allowed
     */
    isUserAllowed(userId: string): boolean;
    /**
     * Check if channel is allowed
     */
    isChannelAllowed(channelId: string): boolean;
    /**
     * Parse command from message
     */
    protected parseCommand(message: InboundMessage): InboundMessage;
    /**
     * Format message for sending
     */
    protected formatMessage(content: string, parseMode?: 'markdown' | 'html' | 'plain'): string;
}
export declare class MockChannel extends BaseChannel {
    private messages;
    private sentMessages;
    constructor(config?: Partial<ChannelConfig>);
    connect(): Promise<void>;
    disconnect(): Promise<void>;
    send(message: OutboundMessage): Promise<DeliveryResult>;
    /**
     * Simulate receiving a message
     */
    simulateMessage(content: string, options?: Partial<InboundMessage>): InboundMessage;
    /**
     * Get received messages
     */
    getMessages(): InboundMessage[];
    /**
     * Get sent messages
     */
    getSentMessages(): OutboundMessage[];
    /**
     * Clear messages
     */
    clear(): void;
}
/**
 * Manages multiple channels
 */
export declare class ChannelManager extends EventEmitter {
    private channels;
    private messageHandlers;
    /**
     * Register a channel
     */
    registerChannel(channel: BaseChannel): void;
    /**
     * Unregister a channel
     */
    unregisterChannel(type: ChannelType): void;
    /**
     * Get a channel
     */
    getChannel(type: ChannelType): BaseChannel | undefined;
    /**
     * Get all channels
     */
    getAllChannels(): BaseChannel[];
    /**
     * Connect all channels
     */
    connectAll(): Promise<void>;
    /**
     * Disconnect all channels
     */
    disconnectAll(): Promise<void>;
    /**
     * Get status of all channels
     */
    getStatus(): Record<ChannelType, ChannelStatus>;
    /**
     * Send to a specific channel
     */
    send(type: ChannelType, message: OutboundMessage): Promise<DeliveryResult>;
    /**
     * Broadcast to all connected channels
     */
    broadcast(message: Omit<OutboundMessage, 'channelId'>): Promise<Map<ChannelType, DeliveryResult>>;
    /**
     * Add message handler
     */
    onMessage(handler: (message: InboundMessage, channel: BaseChannel) => Promise<void>): void;
    /**
     * Handle incoming message
     */
    private handleMessage;
    private outgoingQueue;
    private processingQueue;
    /**
     * Send a message to a user across channels with priority
     */
    sendToUser(channelType: ChannelType, channelId: string, content: string, priority?: 'low' | 'normal' | 'high' | 'urgent'): Promise<DeliveryResult>;
    /**
     * Process the outgoing message queue
     */
    private processQueue;
    /**
     * Shutdown
     */
    shutdown(): Promise<void>;
}
export declare function getChannelManager(): ChannelManager;
export declare function resetChannelManager(): void;
export { TelegramChannel } from './telegram/index.js';
export type { TelegramConfig, TelegramCommand, TelegramUser, TelegramChat, TelegramMessage, TelegramUpdate, } from './telegram/index.js';
export { DiscordChannel } from './discord/index.js';
export type { DiscordConfig, DiscordUser, DiscordMessage, DiscordEmbed, DiscordInteraction, DiscordSlashCommand, DiscordIntent, } from './discord/index.js';
export { SlackChannel } from './slack/index.js';
export type { SlackConfig, SlackUser, SlackMessage, SlackEvent, SlackBlock, SlackSlashCommand, } from './slack/index.js';
export { WebhookServer, getWebhookServer, resetWebhookServer, } from './webhook-server.js';
export type { WebhookServerConfig, WebhookRequest, WebhookResponse, } from './webhook-server.js';
export type { SessionScope, SessionKeyComponents, SessionIsolationConfig, SessionInfo, } from './session-isolation.js';
export { DEFAULT_SESSION_ISOLATION_CONFIG, SessionIsolator, getSessionIsolator, resetSessionIsolator, } from './session-isolation.js';
export type { ChannelIdentity, CanonicalIdentity, IdentityLinkerConfig, } from './identity-links.js';
export { IdentityLinker, getIdentityLinker, resetIdentityLinker, } from './identity-links.js';
export type { RouteAgentConfig, PeerRoute, RouteCondition, ResolvedRoute, PeerRouterConfig, } from './peer-routing.js';
export { PeerRouter, getPeerRouter, resetPeerRouter, } from './peer-routing.js';
export type { PairingStatus, ApprovedSender, PairingRequest, DMPairingConfig, } from './dm-pairing.js';
export { DEFAULT_DM_PAIRING_CONFIG, DMPairingManager, getDMPairing, resetDMPairing, } from './dm-pairing.js';
import { LaneQueue } from '../concurrency/lane-queue.js';
import type { TaskOptions } from '../concurrency/lane-queue.js';
/**
 * Get the singleton LaneQueue for channel message processing.
 *
 * This is separate from the agent executor's lane queue so that
 * channel-level serialization and tool-level serialization each
 * have their own queue configurations.
 */
export declare function getChannelLaneQueue(): LaneQueue;
/**
 * Reset the channel lane queue (for testing).
 */
export declare function resetChannelLaneQueue(): void;
/**
 * Enqueue a message handler for serial execution within a session.
 *
 * Messages for the same session key are processed one at a time
 * (serial by default). Different sessions run in parallel.
 *
 * @param sessionKey - The session key used as the lane ID
 * @param handler - Async function to process the message
 * @param options - Optional task options (e.g., timeout, priority)
 * @returns Promise that resolves with the handler's return value
 */
export declare function enqueueMessage<T>(sessionKey: string, handler: () => Promise<T>, options?: TaskOptions): Promise<T>;
import type { PairingStatus } from './dm-pairing.js';
/**
 * Check if a DM sender is approved via the pairing system.
 *
 * When DM pairing is disabled (the default), this always returns
 * `{ approved: true }` so callers can skip gating logic.
 *
 * @param message - The inbound message to check
 * @returns PairingStatus indicating approval state and pairing code if needed
 */
export declare function checkDMPairing(message: InboundMessage): Promise<PairingStatus>;
