import { createLogger } from "../../../src/utils/logger/index.js";
import { init_logger } from "../../../src/utils/logger.js";
import { WeixinConfigSchema, init_config_schema } from "./config-schema.js";
import { getWorkflowProgressBroker } from "../../../src/agent/workflow/progress-broker.js";
import "../../../src/agent/workflow/index.js";
import { evaluateAccess, resolveDmPolicy } from "../../../src/channels/security.js";
import { createStandardPairingAdapter } from "../../../src/channels/pairing/pairing-store-adapter.js";
import { restoreContextTokens } from "./messaging/inbound.js";
import { listWeixinAccountIds, resolveWeixinAccount } from "./auth/accounts.js";
import { readFrameworkAllowFromList } from "./auth/pairing.js";
import { monitorWeixinProvider } from "./monitor/monitor.js";
import { createWeixinOutboundHandlers, weixinTextChunker } from "./outbound-send.js";
import { normalizeWeixinCronDeliveryToResolved } from "./delivery-to.js";
import { weixinConfigSurface } from "./config-surface.js";
import { weixinOnboardAdapter } from "./adapters/onboard-cli.js";
import { createWeixinWorkflowProgressCapability } from "./workflow-progress.js";
import { isDeepStrictEqual } from "node:util";
//#region extensions/weixin/src/plugin.ts
/**
* Weixin (WeChat ilink) channel — long-poll getUpdates, QR login, direct messages only.
*/
init_logger();
init_config_schema();
const log = createLogger("WeixinPlugin");
var WeixinChannelPlugin = class {
	id = "weixin";
	reload = { configPrefixes: ["channels.weixin"] };
	meta = {
		id: "weixin",
		label: "Weixin",
		selectionLabel: "Weixin (ilink)",
		docsPath: "/channels/weixin",
		blurb: "WeChat via Tencent ilink bot API (QR login, direct chat).",
		order: 3,
		deferConnectUntilAfterListen: true
	};
	capabilities = {
		chatTypes: ["direct"],
		reactions: false,
		threads: false,
		media: true,
		polls: false,
		nativeCommands: false,
		blockStreaming: true
	};
	configSchema = {
		schema: {},
		validate: (raw) => {
			const r = WeixinConfigSchema.safeParse(raw);
			return r.success ? { ok: true } : {
				ok: false,
				errors: [r.error.message]
			};
		}
	};
	cronDelivery = { async normalizeDeliveryTarget(to, sessionStore) {
		const { chatId, accountId } = await normalizeWeixinCronDeliveryToResolved(to, sessionStore);
		return {
			chatId,
			accountId
		};
	} };
	onboard = weixinOnboardAdapter;
	cliLogin = { async runLogin(params) {
		const { runWeixinQrLoginCli } = await import("./cli/qr-login.js");
		return runWeixinQrLoginCli({
			configPath: params.configPath,
			verbose: params.verbose,
			timeoutMs: params.timeoutMs,
			account: params.accountId,
			writeConfig: params.writeConfig
		});
	} };
	configSurface = weixinConfigSurface;
	pairing = createStandardPairingAdapter("weixin");
	defaults = {
		queue: { debounceMs: 0 },
		outbound: { textChunkLimit: 4e3 },
		streaming: { blockStreamingCoalesce: {
			minChars: 200,
			idleMs: 3e3
		} }
	};
	bus;
	cfg;
	abortControllers = /* @__PURE__ */ new Map();
	/** Unregister fn for the workflow-progress capability registered against the global broker. */
	workflowProgressUnregister = null;
	config = {
		listAccountIds: (cfg) => listWeixinAccountIds(cfg),
		resolveAccount: (cfg, accountId) => resolveWeixinAccount(cfg, accountId),
		isConfigured: async (account) => account.configured,
		describeAccount: (account, _cfg) => ({
			accountId: account.accountId,
			channelId: "weixin",
			name: account.name,
			enabled: account.enabled,
			configured: account.configured,
			status: void 0
		})
	};
	security = {
		resolveDmPolicy: ({ account }) => resolveDmPolicy(account.dmPolicy, "open"),
		checkAccess: (ctx, account, _cfg) => {
			const allowFrom = [...account.allowFrom ?? [], ...readFrameworkAllowFromList(account.accountId)];
			return evaluateAccess({
				context: {
					channel: "weixin",
					accountId: account.accountId,
					chatId: ctx.chatId,
					senderId: ctx.senderId,
					senderName: ctx.senderName,
					isGroup: false,
					isDm: true
				},
				dmPolicy: account.dmPolicy,
				allowFrom
			});
		}
	};
	outbound = {
		deliveryMode: "direct",
		chunker: weixinTextChunker,
		chunkerMode: "text",
		textChunkLimit: 4e3,
		...createWeixinOutboundHandlers()
	};
	streaming = { startStream: () => null };
	/** Channel plugin hints (cron targets, media paths). */
	agentPrompt = { augmentSystemPrompt: () => [
		"Weixin (ilink): direct chat only. To send an image or file, use the message tool with action send and set media to a local absolute path or an HTTPS URL; relative paths may fail.",
		"For cron or scheduled delivery to a Weixin contact, set delivery.to to the user Weixin id (ending in @im.wechat) and delivery.accountId to the bot account id, or outbound may pick the wrong account.",
		"When using MEDIA: to attach a file, put the MEDIA: line alone on its own line, not inline with other text."
	].join("\n") };
	async init(options) {
		this.bus = options.bus;
		this.cfg = options.config;
		this.workflowProgressUnregister = getWorkflowProgressBroker().registerChannel(createWeixinWorkflowProgressCapability({ getConfig: () => this.cfg }));
		log.debug("Weixin plugin initialized");
	}
	async start(options) {
		const ids = options?.accountId ? [options.accountId] : listWeixinAccountIds(this.cfg);
		for (const accountId of ids) {
			const account = resolveWeixinAccount(this.cfg, accountId);
			if (!account.enabled || !account.configured || !account.token) continue;
			if (this.abortControllers.has(accountId)) continue;
			restoreContextTokens(account.accountId);
			const ac = new AbortController();
			this.abortControllers.set(accountId, ac);
			monitorWeixinProvider({
				account,
				config: this.cfg,
				bus: this.bus,
				abortSignal: ac.signal
			}).catch((err) => {
				if (err?.name === "AbortError") {
					log.debug({ accountId }, "Weixin monitor stopped");
					return;
				}
				log.error({
					err,
					accountId
				}, "Weixin monitor exited with error");
			});
			log.info({ accountId }, "Weixin monitor started");
		}
	}
	async stop(accountId) {
		const ids = accountId ? [accountId] : [...this.abortControllers.keys()];
		for (const id of ids) {
			const ac = this.abortControllers.get(id);
			if (ac) {
				ac.abort();
				this.abortControllers.delete(id);
			}
		}
		if (!accountId) {
			this.workflowProgressUnregister?.();
			this.workflowProgressUnregister = null;
		}
	}
	channelIsRunning(cfg) {
		return listWeixinAccountIds(cfg).some((id) => {
			const a = resolveWeixinAccount(cfg, id);
			return a.configured && a.enabled !== false && this.abortControllers.has(id);
		});
	}
	async onConfigUpdated(cfg) {
		const prevWx = this.cfg.channels?.weixin;
		const nextWx = cfg.channels?.weixin;
		if (!nextWx || nextWx.enabled !== true) {
			this.cfg = cfg;
			await this.stop();
			return;
		}
		this.cfg = cfg;
		if (isDeepStrictEqual(prevWx, nextWx) && this.channelIsRunning(cfg)) return;
		await this.stop();
		await this.start();
	}
	/**
	* Restart long-poll monitors after credentials were written to disk without a `channels.weixin` JSON
	* delta (e.g. only token files / account index updated). Gateway calls this after QR login completes.
	*
	* Pass `bus` explicitly: if Weixin was disabled at gateway boot, `init()` was skipped and `this.bus` was never set.
	*/
	async reloadMonitorsWithConfig(cfg, bus) {
		this.bus = bus;
		this.cfg = cfg;
		await this.stop();
		await this.start();
	}
};
const weixinPlugin = new WeixinChannelPlugin();
//#endregion
export { WeixinChannelPlugin, weixinPlugin };

//# sourceMappingURL=plugin.js.map