import { generateSessionKey } from "../../../../src/chat-commands/session-key.js";
import { resolveWeixinPairingPath } from "../../../../src/channels/pairing/paths.js";
import { issuePairingChallenge } from "../../../../src/channels/pairing/pairing-challenge.js";
import { evaluateAccess } from "../../../../src/channels/security.js";
import { logger } from "../util/logger.js";
import { MessageItemType } from "../api/types.js";
import { resolveWeixinRootDir } from "../storage/state-dir.js";
import { isMediaItem, setContextToken, weixinMessageToMsgContext } from "./inbound.js";
import { readFrameworkAllowFromList } from "../auth/pairing.js";
import { downloadMediaFromItem } from "../media/media-download.js";
import { isDebugMode } from "./debug-mode.js";
import { sendMessageWeixin } from "./send.js";
import { handleSlashCommand } from "./slash-commands.js";
import { randomBytes } from "node:crypto";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
//#region extensions/weixin/src/messaging/process-message.ts
function extractTextBody(itemList) {
	if (!itemList?.length) return "";
	for (const item of itemList) if (item.type === MessageItemType.TEXT && item.text_item?.text != null) return String(item.text_item.text);
	return "";
}
function mergeAllowFrom(account, accountId) {
	const store = readFrameworkAllowFromList(accountId);
	return [...new Set([...(account.allowFrom ?? []).map(String), ...store])];
}
async function saveMediaBuffer(buffer, contentType, _subdir, maxBytes, originalFilename) {
	const cap = maxBytes ?? 100 * 1024 * 1024;
	if (buffer.length > cap) throw new Error(`weixin media exceeds max bytes (${cap})`);
	const dir = path.join(resolveWeixinRootDir(), "media", "inbound-temp");
	await mkdir(dir, { recursive: true });
	const ext = originalFilename ? path.extname(originalFilename) : contentType?.includes("wav") ? ".wav" : ".bin";
	const fname = `${Date.now()}-${randomBytes(6).toString("hex")}${ext || ".bin"}`;
	const filePath = path.join(dir, fname);
	await writeFile(filePath, buffer);
	return { path: filePath };
}
async function processWeixinInboundMessage(full, deps) {
	const receivedAt = Date.now();
	const senderId = full.from_user_id ?? "";
	if (full.context_token?.trim() && senderId) setContextToken(deps.accountId, senderId, full.context_token, { sendToUserId: senderId });
	const textBody = extractTextBody(full.item_list);
	if (textBody.startsWith("/")) {
		if ((await handleSlashCommand(textBody, {
			to: full.from_user_id ?? "",
			contextToken: full.context_token,
			baseUrl: deps.baseUrl,
			token: deps.token,
			accountId: deps.accountId,
			log: () => {},
			errLog: () => {}
		}, receivedAt, full.create_time_ms)).handled) return;
	}
	const mergedAllow = mergeAllowFrom(deps.account, deps.accountId);
	const access = evaluateAccess({
		context: {
			channel: "weixin",
			accountId: deps.accountId,
			chatId: senderId,
			senderId,
			isGroup: false,
			isDm: true
		},
		dmPolicy: deps.account.dmPolicy ?? "open",
		allowFrom: mergedAllow
	});
	if (!access.allowed) {
		if (access.reason === "pairing-required" && deps.token) try {
			await issuePairingChallenge({
				channel: "weixin",
				pairingFilePath: resolveWeixinPairingPath(deps.accountId),
				accountId: deps.accountId,
				senderId,
				senderIdLine: `Your Weixin user id: ${senderId}`,
				sendPairingReply: async (text) => {
					await sendMessageWeixin({
						to: senderId,
						text,
						opts: {
							baseUrl: deps.baseUrl,
							token: deps.token,
							contextToken: full.context_token,
							routeTag: deps.routeTag
						}
					});
				},
				onReplyError: (err) => {
					logger.warn(`weixin pairing reply failed from=${senderId} err=${String(err)}`);
				}
			});
		} catch (err) {
			logger.warn(`weixin pairing prompt failed from=${senderId} err=${String(err)}`);
		}
		else logger.info(`weixin: dropped message from=${senderId} dmPolicy=${deps.account.dmPolicy ?? "open"} reason=${access.reason ?? "not allowed"}`);
		return;
	}
	const mediaOpts = {};
	const hasDownloadableMedia = (m) => Boolean(m?.encrypt_query_param || m?.full_url);
	const mainMediaItem = full.item_list?.find((i) => i.type === MessageItemType.IMAGE && hasDownloadableMedia(i.image_item?.media)) ?? full.item_list?.find((i) => i.type === MessageItemType.VIDEO && hasDownloadableMedia(i.video_item?.media)) ?? full.item_list?.find((i) => i.type === MessageItemType.FILE && hasDownloadableMedia(i.file_item?.media)) ?? full.item_list?.find((i) => i.type === MessageItemType.VOICE && hasDownloadableMedia(i.voice_item?.media) && !i.voice_item?.text);
	const refMediaItem = !mainMediaItem ? full.item_list?.find((i) => i.type === MessageItemType.TEXT && i.ref_msg?.message_item && isMediaItem(i.ref_msg.message_item))?.ref_msg?.message_item : void 0;
	const mediaItem = mainMediaItem ?? refMediaItem;
	if (mediaItem) {
		const label = refMediaItem ? "ref" : "inbound";
		const downloaded = await downloadMediaFromItem(mediaItem, {
			cdnBaseUrl: deps.cdnBaseUrl,
			saveMedia: saveMediaBuffer,
			log: (m) => logger.debug(m),
			errLog: (m) => logger.warn(m),
			label
		});
		Object.assign(mediaOpts, downloaded);
	}
	const ctx = weixinMessageToMsgContext(full, deps.accountId, mediaOpts);
	const body = ctx.Body?.trim() ?? "";
	const sessionKey = generateSessionKey({
		source: "weixin",
		chatId: senderId,
		senderId,
		isGroup: false,
		accountId: deps.accountId
	});
	const attachments = [];
	if (mediaOpts.decryptedPicPath) {
		const buf = await readFile(mediaOpts.decryptedPicPath);
		attachments.push({
			type: "image",
			mimeType: "image/jpeg",
			data: buf.toString("base64"),
			name: path.basename(mediaOpts.decryptedPicPath)
		});
	} else if (mediaOpts.decryptedVoicePath) {
		const buf = await readFile(mediaOpts.decryptedVoicePath);
		attachments.push({
			type: "audio",
			mimeType: mediaOpts.voiceMediaType ?? "audio/wav",
			data: buf.toString("base64"),
			name: path.basename(mediaOpts.decryptedVoicePath)
		});
	} else if (mediaOpts.decryptedFilePath) {
		const buf = await readFile(mediaOpts.decryptedFilePath);
		attachments.push({
			type: "file",
			mimeType: mediaOpts.fileMediaType ?? "application/octet-stream",
			data: buf.toString("base64"),
			name: path.basename(mediaOpts.decryptedFilePath)
		});
	} else if (mediaOpts.decryptedVideoPath) {
		const buf = await readFile(mediaOpts.decryptedVideoPath);
		attachments.push({
			type: "file",
			mimeType: "video/mp4",
			data: buf.toString("base64"),
			name: path.basename(mediaOpts.decryptedVideoPath)
		});
	}
	if (isDebugMode(deps.accountId)) logger.debug(`weixin debug inbound from=${senderId} bodyLen=${body.length} attachments=${attachments.length}`);
	await deps.bus.publishInbound({
		channel: "weixin",
		sender_id: senderId,
		chat_id: senderId,
		content: body,
		metadata: {
			accountId: deps.accountId,
			sessionKey,
			messageId: full.message_id != null ? String(full.message_id) : void 0,
			isGroup: false,
			isCommand: body.trim().startsWith("/"),
			contextToken: ctx.context_token
		},
		attachments: attachments.length ? attachments : void 0
	});
}
//#endregion
export { processWeixinInboundMessage };

//# sourceMappingURL=process-message.js.map