import { createLogger } from "../../../src/utils/logger/index.js";
import { init_logger } from "../../../src/utils/logger.js";
import { getWorkflowProgressBroker } from "../../../src/agent/workflow/progress-broker.js";
import "../../../src/agent/workflow/index.js";
import { evaluateAccess, resolveDmPolicy, resolveGroupPolicy } from "../../../src/channels/security.js";
import { createStandardPairingAdapter } from "../../../src/channels/pairing/pairing-store-adapter.js";
import { FeishuConfigSchema } from "./schema/config-schema.js";
import { listFeishuAccountIds, resolveFeishuAccount } from "./state/accounts.js";
import { createFeishuSocketModeMonitor } from "./transport/socket-mode/monitor.js";
import { createFeishuWebhookMonitor } from "./transport/webhook/monitor.js";
import { createFeishuOutboundAdapter } from "./outbound/outbound-adapter.js";
import { createFeishuStatusAdapter } from "./status/status-adapter.js";
import { createFeishuDoctorAdapter } from "./status/doctor.js";
import { feishuConfigSurface } from "./ui/config-surface.js";
import { createFeishuStreamingAdapter } from "./streaming/streaming-adapter.js";
import { readFrameworkAllowFromList } from "./auth/pairing.js";
import { addReactionFeishu, editMessageFeishu, getMessageFeishu, listPinsFeishu, listReactionsFeishu, pinMessageFeishu, removeReactionFeishu, unpinMessageFeishu } from "./outbound/actions.js";
import { createFeishuDirectoryAdapter } from "./directory/directory-adapter.js";
import { feishuWhoAmI } from "./tools/tools.js";
import { feishuCliLoginAdapter } from "./adapters/cli-login.js";
import { feishuOnboardAdapter } from "./adapters/onboard-cli.js";
import { handleFeishuChannelMessageAction } from "./actions/message-action-handler.js";
import { createFeishuInboundPipeline } from "./transport/reliability/inbound-pipeline.js";
import { createFeishuWorkflowProgressCapability } from "./workflow-progress.js";
import { isDeepStrictEqual } from "node:util";
//#region extensions/feishu/src/plugin.ts
/**
* Feishu/Lark channel plugin (Socket Mode first).
*
* This is intentionally decomposed into small modules so we can grow toward
* openclaw `extensions/feishu` parity without turning `plugin.ts` into a monolith.
*/
init_logger();
const log = createLogger("FeishuPlugin");
var FeishuChannelPlugin = class {
	id = "feishu";
	reload = { configPrefixes: ["channels.feishu"] };
	meta = {
		id: "feishu",
		label: "Feishu",
		selectionLabel: "Feishu/Lark (飞书)",
		docsPath: "/channels/feishu",
		blurb: "Feishu/Lark enterprise messaging (Socket Mode).",
		order: 4,
		deferConnectUntilAfterListen: true
	};
	capabilities = {
		chatTypes: ["direct", "channel"],
		reactions: true,
		threads: true,
		media: true,
		polls: false,
		nativeCommands: false,
		blockStreaming: false,
		edit: true,
		reply: true
	};
	defaults = {
		queue: { debounceMs: 350 },
		outbound: { textChunkLimit: 4e3 },
		streaming: { blockStreamingCoalesce: {
			minChars: 200,
			idleMs: 2500
		} }
	};
	configSchema = {
		schema: {},
		validate: (raw) => {
			const r = FeishuConfigSchema.safeParse(raw);
			return r.success ? { ok: true } : {
				ok: false,
				errors: [r.error.message]
			};
		}
	};
	configSurface = feishuConfigSurface;
	pairing = createStandardPairingAdapter("feishu");
	onboard = feishuOnboardAdapter;
	cliLogin = feishuCliLoginAdapter;
	bus;
	cfg;
	abortControllers = /* @__PURE__ */ new Map();
	inboundPipeline;
	/** Unregister fn for the workflow-progress capability registered against the global broker. */
	workflowProgressUnregister = null;
	config = {
		listAccountIds: (cfg) => listFeishuAccountIds(cfg),
		resolveAccount: (cfg, accountId) => resolveFeishuAccount(cfg, accountId),
		isConfigured: async (account) => account.configured,
		describeAccount: (account) => ({
			accountId: account.accountId,
			channelId: "feishu",
			enabled: account.enabled,
			configured: account.configured,
			status: account.configured ? void 0 : "unconfigured"
		})
	};
	security = {
		resolveDmPolicy: ({ account }) => resolveDmPolicy(account.dmPolicy, "open"),
		resolveGroupPolicy: ({ account }) => resolveGroupPolicy(account.groupPolicy, "allowlist"),
		checkAccess: (ctx, account, _cfg) => {
			const isDm = !ctx.isGroup;
			const frameworkAllowFrom = readFrameworkAllowFromList(account.accountId);
			const allowFrom = [...(isDm ? account.allowFrom : account.groupAllowFrom ?? account.allowFrom) ?? [], ...frameworkAllowFrom];
			if (isDm) return evaluateAccess({
				context: {
					channel: "feishu",
					accountId: account.accountId,
					chatId: ctx.chatId,
					senderId: ctx.senderId,
					senderName: ctx.senderName,
					isGroup: false,
					isDm: true
				},
				dmPolicy: account.dmPolicy,
				allowFrom
			});
			return evaluateAccess({
				context: {
					channel: "feishu",
					accountId: account.accountId,
					chatId: ctx.chatId,
					senderId: ctx.senderId,
					senderName: ctx.senderName,
					isGroup: true,
					isDm: false
				},
				groupPolicy: account.groupPolicy,
				allowFrom
			});
		}
	};
	outbound = createFeishuOutboundAdapter();
	streaming = createFeishuStreamingAdapter(() => this.cfg);
	status = createFeishuStatusAdapter();
	doctor = createFeishuDoctorAdapter();
	directory = createFeishuDirectoryAdapter();
	actions = { handleAction: handleFeishuChannelMessageAction };
	agentTools = [
		{
			name: "feishu_read",
			description: "Read a Feishu message by messageId (debug/utility).",
			execute: async (toolCtx, args) => {
				const messageId = typeof args?.messageId === "string" ? args.messageId : toolCtx.messageId;
				if (!messageId) throw new Error("feishu_read requires messageId");
				return await getMessageFeishu({
					cfg: this.cfg,
					accountId: toolCtx.accountId,
					messageId
				});
			}
		},
		{
			name: "feishu_edit",
			description: "Edit a Feishu message by messageId.",
			execute: async (toolCtx, args) => {
				const messageId = typeof args?.messageId === "string" ? args.messageId : toolCtx.messageId;
				const text = typeof args?.text === "string" ? args.text : "";
				if (!messageId) throw new Error("feishu_edit requires messageId");
				if (!text.trim()) throw new Error("feishu_edit requires text");
				return await editMessageFeishu({
					cfg: this.cfg,
					accountId: toolCtx.accountId,
					messageId,
					text
				});
			}
		},
		{
			name: "feishu_scopes_probe",
			description: "Probe Feishu credentials/scopes (placeholder for full docs/wiki/drive tools).",
			execute: async (toolCtx) => {
				return await feishuWhoAmI({
					cfg: this.cfg,
					accountId: toolCtx.accountId
				});
			}
		},
		{
			name: "feishu_react",
			description: "Add/remove/list reactions for a message.",
			execute: async (toolCtx, args) => {
				const a = args;
				const messageId = typeof a?.messageId === "string" ? a.messageId : toolCtx.messageId;
				if (!messageId) throw new Error("feishu_react requires messageId");
				if (!(resolveFeishuAccount(this.cfg, toolCtx.accountId ?? "default").actions?.reactions !== false)) throw new Error("Feishu reactions are disabled via channels.feishu.actions.reactions");
				if (a?.list === true) return await listReactionsFeishu({
					cfg: this.cfg,
					accountId: toolCtx.accountId,
					messageId,
					emojiType: typeof a?.emojiType === "string" ? a.emojiType : void 0
				});
				if (a?.remove === true) {
					const reactionId = typeof a?.reactionId === "string" ? a.reactionId : "";
					if (!reactionId) throw new Error("feishu_react remove requires reactionId");
					return await removeReactionFeishu({
						cfg: this.cfg,
						accountId: toolCtx.accountId,
						messageId,
						reactionId
					});
				}
				const emojiType = typeof a?.emojiType === "string" ? a.emojiType : "";
				if (!emojiType) throw new Error("feishu_react requires emojiType");
				return await addReactionFeishu({
					cfg: this.cfg,
					accountId: toolCtx.accountId,
					messageId,
					emojiType
				});
			}
		},
		{
			name: "feishu_pins",
			description: "Pin/unpin/list pins for a chat.",
			execute: async (toolCtx, args) => {
				const a = args;
				const action = typeof a?.action === "string" ? a.action : "";
				if (action === "list") {
					const chatId = typeof a?.chatId === "string" ? a.chatId : toolCtx.chatId;
					if (!chatId) throw new Error("feishu_pins list requires chatId");
					return await listPinsFeishu({
						cfg: this.cfg,
						accountId: toolCtx.accountId,
						chatId,
						startTime: typeof a?.startTime === "string" ? a.startTime : void 0,
						endTime: typeof a?.endTime === "string" ? a.endTime : void 0,
						pageSize: typeof a?.pageSize === "number" ? a.pageSize : void 0,
						pageToken: typeof a?.pageToken === "string" ? a.pageToken : void 0
					});
				}
				const messageId = typeof a?.messageId === "string" ? a.messageId : toolCtx.messageId;
				if (!messageId) throw new Error("feishu_pins requires messageId");
				if (action === "pin") return await pinMessageFeishu({
					cfg: this.cfg,
					accountId: toolCtx.accountId,
					messageId
				});
				if (action === "unpin") return await unpinMessageFeishu({
					cfg: this.cfg,
					accountId: toolCtx.accountId,
					messageId
				});
				throw new Error("feishu_pins requires action: pin | unpin | list");
			}
		}
	];
	async init(options) {
		this.bus = options.bus;
		this.cfg = options.config;
		const defaultDebounce = this.defaults.queue?.debounceMs ?? 350;
		this.inboundPipeline = createFeishuInboundPipeline({
			bus: this.bus,
			defaultDebounceMs: defaultDebounce,
			onError: (err, items) => {
				log.error({
					err,
					count: items.length
				}, "Feishu inbound pipeline flush failed");
			}
		});
		this.workflowProgressUnregister = getWorkflowProgressBroker().registerChannel(createFeishuWorkflowProgressCapability({ getConfig: () => this.cfg }));
		log.debug("Feishu plugin initialized");
	}
	async start(options) {
		const section = this.cfg.channels?.feishu;
		if (!section || section.enabled !== true) return;
		const ids = options?.accountId ? [options.accountId] : listFeishuAccountIds(this.cfg);
		for (const accountId of ids) {
			const account = resolveFeishuAccount(this.cfg, accountId);
			if (!account.enabled || !account.configured) continue;
			if (this.abortControllers.has(accountId)) continue;
			const ac = new AbortController();
			this.abortControllers.set(accountId, ac);
			const defaultDebounce = this.defaults.queue?.debounceMs ?? 350;
			const enqueueInbound = (work) => {
				const p = this.inboundPipeline;
				if (!p) return this.bus.publishInbound(work.inbound);
				return p.enqueue(work);
			};
			const monitor = createFeishuSocketModeMonitor({
				account,
				config: this.cfg,
				enqueueInbound,
				inboundDebounceDefaultMs: defaultDebounce,
				abortSignal: ac.signal,
				security: { checkAccess: (ctx) => this.security.checkAccess?.(ctx, account, this.cfg) }
			});
			(account.connectionMode === "webhook" ? createFeishuWebhookMonitor({
				account,
				config: this.cfg,
				enqueueInbound,
				inboundDebounceDefaultMs: defaultDebounce,
				abortSignal: ac.signal,
				security: { checkAccess: (ctx) => this.security.checkAccess?.(ctx, account, this.cfg) }
			}) : monitor).run().catch((err) => {
				if (err?.name === "AbortError") {
					log.debug({ accountId }, "Feishu monitor stopped");
					return;
				}
				log.error({
					err,
					accountId
				}, "Feishu monitor exited with error");
			});
			log.info({
				accountId,
				mode: account.connectionMode
			}, "Feishu monitor started");
		}
	}
	async stop(accountId) {
		try {
			await this.inboundPipeline?.flushAll();
		} catch (err) {
			log.warn({ err }, "Feishu inbound pipeline flushAll failed");
		}
		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 listFeishuAccountIds(cfg).some((id) => {
			const a = resolveFeishuAccount(cfg, id);
			return a.enabled !== false && a.configured && this.abortControllers.has(id);
		});
	}
	async onConfigUpdated(cfg) {
		const prev = this.cfg.channels?.feishu;
		const next = cfg.channels?.feishu;
		if (!next || next.enabled !== true) {
			this.cfg = cfg;
			await this.stop();
			return;
		}
		this.cfg = cfg;
		if (isDeepStrictEqual(prev, next) && this.channelIsRunning(cfg)) return;
		await this.stop();
		await this.start();
	}
};
const feishuPlugin = new FeishuChannelPlugin();
//#endregion
export { FeishuChannelPlugin, feishuPlugin };

//# sourceMappingURL=plugin.js.map