import { createLogger } from "../utils/logger/index.js";
import { init_logger } from "../utils/logger.js";
import { ChannelHealthMonitor } from "./health-monitor.js";
import { ChannelHeartbeatScheduler } from "./heartbeat-scheduler.js";
import { ChannelPluginRegistry } from "./plugin-registry.js";
import { ChannelOutboundSender } from "./outbound-sender.js";
import { ChannelLifecycleSupervisor } from "./lifecycle-supervisor.js";
//#region src/channels/manager.ts
init_logger();
const log = createLogger("ChannelManager");
var ChannelManager = class {
	config;
	registry = new ChannelPluginRegistry();
	healthMonitor = new ChannelHealthMonitor();
	lifecycle;
	heartbeat;
	outbound;
	sessionModelHooks;
	constructor(config, bus) {
		this.config = config;
		this.heartbeat = new ChannelHeartbeatScheduler({
			getConfig: () => this.config,
			healthMonitor: this.healthMonitor,
			requestSoftRestart: (channelId) => {
				this.lifecycle.softRestart(channelId);
			}
		});
		this.lifecycle = new ChannelLifecycleSupervisor({
			bus,
			registry: this.registry,
			getConfig: () => this.config,
			getSessionModelHooks: () => this.sessionModelHooks,
			onPluginStarted: (plugin) => this.heartbeat.schedule(plugin),
			onPluginStopped: (pluginId) => this.heartbeat.clear(pluginId)
		});
		this.outbound = new ChannelOutboundSender({
			registry: this.registry,
			getConfig: () => this.config
		});
	}
	setOutboundHooks(hooks) {
		this.outbound.setHooks(hooks);
	}
	/** Call before `initialize()` so plugins can persist per-session model overrides. */
	setSessionModelHooks(hooks) {
		this.sessionModelHooks = hooks;
	}
	enableOutboundPersistence(agentDir) {
		this.outbound.enablePersistence(agentDir);
	}
	registerPlugin(plugin) {
		this.registry.register(plugin);
	}
	getPlugin(id) {
		return this.registry.get(id);
	}
	getAllPlugins() {
		return this.registry.all();
	}
	/** Backward-compat alias for `getAllPlugins`. */
	getAllChannels() {
		return this.registry.all();
	}
	/** Channel IDs whose runtime reports connected (e.g. Telegram polling active). */
	getRunningChannels() {
		return this.registry.runningChannelIds(this.config, (id) => this.lifecycle.isInitialized(id));
	}
	initialize() {
		return this.lifecycle.initialize();
	}
	start(options) {
		return this.lifecycle.start(options);
	}
	startDeferredConnects() {
		return this.lifecycle.startDeferredConnects();
	}
	async stop() {
		await this.lifecycle.stop();
		this.heartbeat.clearAll();
	}
	stopChannel(channelId) {
		return this.lifecycle.stopChannel(channelId);
	}
	startChannel(channelId) {
		return this.lifecycle.startChannel(channelId);
	}
	listDeferConnectChannelIds(cfg) {
		return this.lifecycle.listDeferConnectChannelIds(cfg);
	}
	send(msg, options) {
		return this.outbound.send(msg, options);
	}
	replayPendingOutboundMessages() {
		return this.outbound.replayPending();
	}
	startStream(channel, chatId, accountId, opts) {
		const plugin = this.registry.get(channel);
		if (!plugin) {
			log.error({ channel }, "Unknown channel");
			return null;
		}
		return plugin.streaming?.startStream?.({
			chatId,
			accountId,
			threadId: opts?.threadId,
			replyToMessageId: opts?.replyToMessageId
		}) ?? null;
	}
	async getChannelStatus(channel) {
		const plugin = this.registry.get(channel);
		if (!plugin) return { error: "Unknown channel" };
		if (!plugin.status?.buildChannelSummary) return { status: "unknown" };
		try {
			const accountId = plugin.config.listAccountIds(this.config)[0] ?? "default";
			const account = plugin.config.resolveAccount(this.config, accountId);
			return await plugin.status.buildChannelSummary({
				account,
				cfg: this.config,
				defaultAccountId: accountId,
				snapshot: plugin.status.defaultRuntime ?? {
					accountId,
					channelId: channel,
					enabled: true,
					configured: true
				}
			});
		} catch (err) {
			return { error: String(err) };
		}
	}
	/**
	* Optional channel hook before `AgentService` consumes an inbound message
	* (e.g. Feishu card-action triggers).
	*/
	async dispatchInboundMessageAction(msg) {
		const handle = this.registry.get(msg.channel)?.actions?.handleAction;
		if (!handle) return;
		const meta = msg.metadata;
		if (msg.channel !== "feishu" || meta?.feishuEventType !== "card.action.trigger") return;
		const cardAction = meta.cardAction;
		const actionTag = cardAction && typeof cardAction.tag === "string" && cardAction.tag.trim() ? cardAction.tag.trim() : "feishu.card_action";
		const cardCtx = meta.cardContext;
		const openMsg = cardCtx && typeof cardCtx.open_message_id === "string" ? cardCtx.open_message_id.trim() : "";
		const fallbackMsgId = typeof meta.messageId === "string" ? meta.messageId.trim() : "";
		const messageId = openMsg || fallbackMsgId;
		const accountId = typeof meta.accountId === "string" && meta.accountId.trim() ? meta.accountId.trim() : "default";
		try {
			await handle({
				action: actionTag,
				data: JSON.stringify({
					cardAction: meta.cardAction,
					cardContext: meta.cardContext,
					cardActionText: meta.cardActionText
				}),
				messageId,
				senderId: msg.sender_id,
				chatId: msg.chat_id,
				accountId,
				metadata: {
					feishuEventType: meta.feishuEventType,
					raw: meta.raw,
					sessionKey: meta.sessionKey,
					userContent: msg.content
				}
			});
		} catch (err) {
			const em = err instanceof Error ? err.message : String(err);
			log.error({
				err,
				channel: msg.channel,
				accountId,
				em
			}, "dispatchInboundMessageAction failed");
		}
	}
	async updateConfig(config) {
		this.config = config;
		await this.lifecycle.forwardConfigUpdate(config);
		log.info("Channel config updated");
	}
	/** Replace in-memory config without running plugin `onConfigUpdated` hooks. */
	setRuntimeConfig(config) {
		this.config = config;
	}
	getRuntimeSnapshot() {
		return {
			...this.lifecycle.snapshot(),
			pluginIds: this.registry.ids(),
			channelHealth: this.healthMonitor.toJSON()
		};
	}
	getHealthMonitor() {
		return this.healthMonitor;
	}
};
function createChannelManager(config, bus) {
	return new ChannelManager(config, bus);
}
//#endregion
export { ChannelManager, createChannelManager };

//# sourceMappingURL=manager.js.map