/**
 * bridge.js — 外部平台接入 REST API
 *
 * 管理 Telegram / 飞书 / QQ 等外部消息平台的连接。
 */

import fs from "fs";
import path from "path";
import { Hono } from "hono";
import { safeJson } from "../hono-helpers.ts";
import { debugLog } from "../../lib/debug-log.ts";
import { parseSessionKey, collectKnownUsers, KNOWN_PLATFORMS } from "../../lib/bridge/session-key.ts";
import { isBridgeOwner, resolveBridgeOwnerUserId } from "../../lib/bridge/owner-policy.ts";
import { collectBridgeMediaAllowedRoots, isInsideBridgeMediaRoot } from "../../lib/bridge/media-roots.ts";
import { t } from "../../lib/i18n.ts";
import { resolveAgent, resolveAgentStrict } from "../utils/resolve-agent.ts";
import { telegramBotOptions } from "../../lib/net/outbound-proxy.ts";
import {
  collectSecretPatchPaths,
  isMaskedSecretValue,
  maskSecretValue,
  resolveSecretPatch,
} from "../../shared/secret-custody.ts";
import { denySecretMutationWithoutScope, denyWithoutScope } from "../http/capability-guard.ts";
import { recordSecurityAuditEvent } from "../http/security-audit.ts";
import { normalizeBridgePermissionMode, SESSION_PERMISSION_MODES } from "../../core/session-permission-mode.ts";

const MAX_BRIDGE_MEDIA_SIZE = 50 * 1024 * 1024;
const FEISHU_TENANT_TOKEN_URL = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";

function feishuLongConnectionInfo() {
  return {
    eventDelivery: "long_connection",
    callbackUrlRequired: false,
    longConnection: {
      status: "not_tested",
      reason: "bridge/test validates credentials only; the runtime WSClient reports live long-connection status after the connector is enabled.",
    },
  };
}

function feishuTestInfo({ credentialOk, response, data }: { credentialOk?: any; response?: any; data?: any } = {}) {
  const logId = data?.error?.log_id || data?.log_id || null;
  return {
    credentialOk,
    ...feishuLongConnectionInfo(),
    ...(response ? { httpStatus: response.status } : {}),
    ...(data?.code !== undefined ? { feishuCode: data.code } : {}),
    ...(data?.msg ? { feishuMessage: data.msg } : {}),
    ...(logId ? { logId } : {}),
  };
}

function normalizeBridgeManagerRef(ref: any) {
  if (ref && typeof ref.get === "function") {
    return {
      get: ref.get,
      ensureReady: ref.ensureReady || ref.get,
      getState: ref.getState || (() => ({ ready: !!ref.get(), initializing: false, error: null })),
    };
  }
  if (typeof ref === "function") {
    return {
      get: ref,
      ensureReady: ref,
      getState: () => ({ ready: !!ref(), initializing: false, error: null }),
    };
  }
  return {
    get: () => ref || null,
    ensureReady: async () => ref || null,
    getState: () => ({ ready: !!ref, initializing: false, error: null }),
  };
}

function bridgeUnavailable(c: any, state: { error?: any; initializing?: any } = {}) {
  const error = state.error
    ? `bridge manager unavailable: ${state.error}`
    : "bridge manager is still starting";
  return c.json({
    ok: false,
    error,
    bridge: {
      ready: false,
      initializing: state.initializing !== false,
      error: state.error || null,
    },
  }, 503);
}

export function buildBridgeStatus(engine: any, manager: any, agent: any) {
  const live = manager?.getStatus?.(agent.id) || {};
  const bridge = agent.config?.bridge || {};
  const index = engine.getBridgeIndex?.(agent.id) || {};

  const platformStatus = (plat: any, cfg: any, extraFields: any) => {
    return {
      ...extraFields,
      enabled: !!cfg?.enabled,
      status: live[plat]?.status || "disconnected",
      error: live[plat]?.error || null,
      agentId: agent.id,
    };
  };

  const tgToken = bridge.telegram?.token || "";
  const fsAppId = bridge.feishu?.appId || "";
  const fsAppSecret = bridge.feishu?.appSecret || "";

  const ownerDict = {};
  for (const plat of KNOWN_PLATFORMS) {
    const o = resolveBridgeOwnerUserId({ platform: plat, agent, index });
    if (o) ownerDict[plat] = o;
  }

  const readOnly = engine.getBridgeReadOnly?.() === true;
  const permissionMode = engine.getBridgePermissionMode?.()
    || normalizeBridgePermissionMode({ readOnly });
  const receiptEnabled = engine.getBridgeReceiptEnabled?.() !== false;

  return {
    agentId: agent.id,
    telegram: platformStatus("telegram", bridge.telegram, {
      configured: !!tgToken, token: maskSecretValue(tgToken),
    }),
    feishu: platformStatus("feishu", bridge.feishu, {
      configured: !!(fsAppId && fsAppSecret), appId: fsAppId, appSecret: maskSecretValue(fsAppSecret),
    }),
    qq: platformStatus("qq", bridge.qq, {
      configured: !!(bridge.qq?.appID && (bridge.qq?.appSecret || bridge.qq?.token)),
      appID: bridge.qq?.appID || "",
      appSecret: maskSecretValue(bridge.qq?.appSecret || bridge.qq?.token || ""),
    }),
    wechat: platformStatus("wechat", bridge.wechat, {
      configured: !!bridge.wechat?.botToken,
      token: maskSecretValue(bridge.wechat?.botToken || ""),
    }),
    permissionMode,
    readOnly,
    receiptEnabled,
    knownUsers: collectKnownUsers(index),
    owner: ownerDict,
  };
}

export function createBridgeRoute(engine: any, bridgeManagerRef: any) {
  const route = new Hono();
  const bridgeRef = normalizeBridgeManagerRef(bridgeManagerRef);

  function resolveBridgeManager() {
    return bridgeRef.get?.() || null;
  }

  async function ensureBridgeManager() {
    const existing = resolveBridgeManager();
    if (existing) return existing;
    try {
      return await bridgeRef.ensureReady?.() || null;
    } catch {
      return null;
    }
  }

  /** 获取所有平台连接状态（从 agent.config.bridge 读取） */
  route.get("/bridge/status", async (c) => {
    const agent = resolveAgent(engine, c);
    const manager = resolveBridgeManager();
    const bridgeState = bridgeRef.getState?.() || { ready: !!manager, initializing: false, error: null };
    return c.json({
      ...buildBridgeStatus(engine, manager, agent),
      bridgeReady: !!manager,
      bridgeInitializing: !!bridgeState.initializing,
      bridgeError: bridgeState.error || null,
    });
  });

  /** 设置 owner（哪个账号是你）— 写入 agent.config.bridge */
  route.post("/bridge/owner", async (c) => {
    const body = await safeJson(c);
    const { platform, userId } = body;
    if (!platform || !KNOWN_PLATFORMS.includes(platform)) {
      return c.json({ ok: false, error: "invalid platform" });
    }
    const scopeDenied = denyWithoutScope(c, "bridge.manage");
    if (scopeDenied) return scopeDenied;
    const agent = resolveAgentStrict(engine, c);
    agent.updateConfig({ bridge: { [platform]: { owner: userId || null } } });
    debugLog()?.log("api", `POST /api/bridge/owner agent=${agent.id} platform=${platform} owner=${userId ? "[set]" : "[cleared]"}`);
    return c.json({ ok: true });
  });

  /** 保存凭证 + 启停平台（写入 agent.config.bridge） */
  route.post("/bridge/config", async (c) => {
    const body = await safeJson(c);
    const { platform, credentials, enabled } = body;
    if (!platform || !KNOWN_PLATFORMS.includes(platform)) {
      return c.json({ error: "invalid platform" }, 400);
    }
    const scopeDenied = denyWithoutScope(c, "bridge.manage");
    if (scopeDenied) return scopeDenied;
    const secretFields = credentials
      ? collectSecretPatchPaths({ credentials }, bridgeSecretKeys(platform))
      : [];
    const secretDenied = denySecretMutationWithoutScope(c, secretFields);
    if (secretDenied) return secretDenied;

    const agent = resolveAgentStrict(engine, c);
    const agentId = agent.id;

    const bridgeCfg = agent.config?.bridge?.[platform] || {};
    const patch = { ...bridgeCfg };

    if (credentials) {
      Object.assign(patch, resolveBridgeCredentials(platform, credentials, bridgeCfg));
    }
    if (typeof enabled === "boolean") patch.enabled = enabled;

    agent.updateConfig({ bridge: { [platform]: patch } });

    // Start/stop
    if (patch.enabled) {
      const manager = await ensureBridgeManager();
      if (!manager) return bridgeUnavailable(c, bridgeRef.getState?.() || {});
      manager.startPlatformFromConfig(platform, patch, agentId);
    } else {
      resolveBridgeManager()?.stopPlatform(platform, agentId);
    }

    debugLog()?.log("api", `POST /api/bridge/config agent=${agentId} platform=${platform} enabled=${!!patch.enabled}`);
    recordSecurityAuditEvent(c, engine, {
      action: "settings.bridge.config.update",
      target: `bridge.${platform}`,
      secretFields,
      metadata: { agentId, platform, enabled: typeof enabled === "boolean" ? enabled : null },
    } as any);
    return c.json({ ok: true });
  });

  /** 更新 bridge 总设置（permissionMode / legacy readOnly / receiptEnabled）— global preferences */
  route.post("/bridge/settings", async (c) => {
    const body = await safeJson(c);
    const scopeDenied = denyWithoutScope(c, "bridge.manage");
    if (scopeDenied) return scopeDenied;
    const { permissionMode, readOnly, receiptEnabled } = body;
    if (typeof permissionMode === "string") {
      const normalized = normalizeBridgePermissionMode({ permissionMode });
      if (normalized !== permissionMode) {
        return c.json({ ok: false, error: "invalid bridge permission mode" }, 400);
      }
      engine.setBridgePermissionMode?.(normalized);
    } else if (typeof readOnly === "boolean") {
      engine.setBridgeReadOnly(readOnly);
      engine.setBridgePermissionMode?.(
        readOnly ? SESSION_PERMISSION_MODES.READ_ONLY : SESSION_PERMISSION_MODES.AUTO,
      );
    }
    if (typeof receiptEnabled === "boolean") {
      engine.setBridgeReceiptEnabled(receiptEnabled);
    }
    debugLog()?.log(
      "api",
      `POST /api/bridge/settings permissionMode=${permissionMode} readOnly=${readOnly} receiptEnabled=${receiptEnabled}`,
    );
    const savedPermissionMode = engine.getBridgePermissionMode?.()
      || normalizeBridgePermissionMode({ readOnly: engine.getBridgeReadOnly() });
    return c.json({
      ok: true,
      permissionMode: savedPermissionMode,
      readOnly: engine.getBridgeReadOnly(),
      receiptEnabled: engine.getBridgeReceiptEnabled(),
    });
  });

  /** 停止指定平台 */
  route.post("/bridge/stop", async (c) => {
    const body = await safeJson(c);
    const { platform } = body;
    if (!platform) {
      return c.json({ error: "platform required" }, 400);
    }
    const scopeDenied = denyWithoutScope(c, "bridge.manage");
    if (scopeDenied) return scopeDenied;

    const agent = resolveAgentStrict(engine, c);
    resolveBridgeManager()?.stopPlatform(platform, agent.id);
    agent.updateConfig({ bridge: { [platform]: { enabled: false } } });

    debugLog()?.log("api", `POST /api/bridge/stop agent=${agent.id} platform=${platform}`);
    return c.json({ ok: true });
  });

  /** 获取最近消息日志（实时内存缓冲） */
  route.get("/bridge/messages", async (c) => {
    const limit = parseInt(c.req.query("limit"), 10) || 50;
    const agent = resolveAgent(engine, c);
    return c.json({ messages: resolveBridgeManager()?.getMessages(limit, agent.id) || [] });
  });

  /** 获取 bridge session 列表 */
  route.get("/bridge/sessions", async (c) => {
    const platform = c.req.query("platform"); // optional filter
    const agent = resolveAgent(engine, c);
    const index = engine.getBridgeIndex(agent.id);
    const bridgeDir = path.join(agent.sessionDir, "bridge");
    const sessions = [];

    for (const [sessionKey, raw] of Object.entries(index) as [string, any][]) {
      // 兼容旧格式（字符串）和新格式（对象）
      const entry = typeof raw === "string" ? { file: raw } : raw;
      const file = entry.file;
      if (!file) continue;

      // 解析 sessionKey → 平台 + 类型
      const { platform: plat, chatType, chatId } = parseSessionKey(sessionKey);

      // 按平台过滤
      if (platform && plat !== platform) continue;

      // 获取最后修改时间
      let lastActive = null;
      const fp = path.resolve(bridgeDir, file);
      const bridgeRoot = path.resolve(bridgeDir);
      if (!fp.startsWith(bridgeRoot + path.sep)) continue;
      try {
        const stat = fs.statSync(fp);
        lastActive = stat.mtimeMs;
      } catch {}

      const userId = entry.userId || (plat === "wechat" && chatType === "dm" ? chatId : null);
      const aliases = Array.isArray(entry.qqPrincipal?.aliases) ? entry.qqPrincipal.aliases : undefined;
      const isOwner = isBridgeOwner({ platform: plat, chatType, userId, aliases, agent });

      sessions.push({
        sessionKey, platform: plat, chatType, chatId, file, sessionPath: fp, lastActive,
        displayName: entry.name || null,
        avatarUrl: entry.avatarUrl || null,
        isOwner,
      });
    }

    // 按最后活跃时间排序
    sessions.sort((a, b) => (b.lastActive || 0) - (a.lastActive || 0));
    return c.json({ sessions });
  });

  /** 读取指定 bridge session 的消息 */
  route.get("/bridge/sessions/:sessionKey/messages", async (c) => {
    const sessionKey = c.req.param("sessionKey");
    const agent = resolveAgent(engine, c);
    const index = engine.getBridgeIndex(agent.id);
    const raw = index[sessionKey];
    const file = typeof raw === "string" ? raw : raw?.file;
    if (!file) return c.json({ error: "session not found", messages: [] });

    const bridgeDir = path.join(agent.sessionDir, "bridge");
    const fp = path.resolve(bridgeDir, file);

    // 防止 path traversal
    if (!fp.startsWith(path.resolve(bridgeDir) + path.sep)) {
      return c.json({ error: "invalid session path", messages: [] });
    }

    try {
      const rawContent = fs.readFileSync(fp, "utf-8");
      const lines = rawContent.trim().split("\n").map(l => {
        try { return JSON.parse(l); } catch { return null; }
      }).filter(Boolean);

      const messages = [];
      for (const line of lines) {
        if (line.type !== "message") continue;
        const msg = line.message;
        if (!msg || (msg.role !== "user" && msg.role !== "assistant")) continue;

        let textContent = "";
        let mediaCount = 0;
        if (Array.isArray(msg.content)) {
          for (const b of msg.content) {
            if (b.type === "text" && b.text) textContent += b.text;
            if (b.type === "image") mediaCount++;
          }
        } else if (typeof msg.content === "string") {
          textContent = msg.content;
        }

        const hasMedia = mediaCount > 0;
        if (!textContent && !hasMedia) continue;
        messages.push({
          role: msg.role,
          content: textContent || (hasMedia ? `[图片 x${mediaCount}]` : ""),
          hasMedia,
          mediaCount,
          ts: line.timestamp || null,
        });
      }

      return c.json({ messages });
    } catch (err) {
      return c.json({ error: err.message, messages: [] });
    }
  });

  /** 重置 bridge session（清除上下文，下次消息新建 session） */
  route.post("/bridge/sessions/:sessionKey/reset", async (c) => {
    const sessionKey = c.req.param("sessionKey");
    const agent = resolveAgentStrict(engine, c);
    const agentId = agent.id;
    const index = engine.getBridgeIndex(agentId);
    const raw = index[sessionKey];
    if (!raw) return c.json({ ok: false, error: "session not found" });

    // 保留元数据（name, avatarUrl），只删 file 引用
    const entry = typeof raw === "string" ? {} : { ...raw };
    delete entry.file;
    index[sessionKey] = entry;
    engine.saveBridgeIndex(index, agentId);

    return c.json({ ok: true });
  });

  /** 公开给外部平台拉取的临时媒体 URL（由 MediaPublisher token 控制） */
  route.get("/bridge/media/:token", async (c) => {
    const token = c.req.param("token");
    const entry = resolveBridgeManager()?.mediaPublisher?.resolve?.(token);
    if (!entry) return c.text("media not found", 404);

    let stat;
    try {
      stat = fs.statSync(entry.realPath);
      if (!stat.isFile()) return c.text("media not found", 404);
    } catch {
      return c.text("media not found", 404);
    }
    if (stat.size > MAX_BRIDGE_MEDIA_SIZE) {
      return c.text("media too large", 413);
    }

    const filename = entry.filename || path.basename(entry.realPath);
    const disposition = isInlineBridgeMediaMime(entry.mime) ? "inline" : "attachment";
    const headers = new Headers({
      "content-type": entry.mime || "application/octet-stream",
      "content-length": String(stat.size),
      "content-disposition": `${disposition}; filename*=UTF-8''${encodeRfc5987ValueChars(filename)}`,
      "cache-control": "no-store",
      "x-content-type-options": "nosniff",
    });
    return new Response(fs.readFileSync(entry.realPath), { headers });
  });

  /** 发送媒体到 bridge 平台（桌面端推送文件） */
  route.post("/bridge/send-media", async (c) => {
    const body = await safeJson(c);
    const { platform, chatId, filePath } = body;
    if (!platform || !chatId || !filePath) {
      return c.json({ error: "platform, chatId, filePath required" }, 400);
    }

    const agent = resolveAgentStrict(engine, c);

    // 路径安全检查：对齐 Bridge runtime 的媒体发送白名单。
    const allowedRoots = collectBridgeMediaAllowedRoots(engine, { agentId: agent.id, agent });

    // 先检查文件是否存在
    const resolved = path.resolve(filePath);
    if (!fs.existsSync(resolved)) {
      return c.json({ error: "file not found" }, 404);
    }

    // 用 realpathSync 解析 symlink，防止 symlink 绕过白名单
    let realPath;
    try { realPath = fs.realpathSync(resolved); }
    catch { return c.json({ error: "file not found" }, 404); }

    const isSafe = isInsideBridgeMediaRoot(realPath, allowedRoots);
    if (!isSafe) {
      return c.json({ error: "path outside allowed roots" }, 403);
    }

    // Fix 3: 文件大小保护（50MB 上限，避免同步读大文件卡事件循环）
    try {
      const stat = fs.statSync(realPath);
      if (stat.size > MAX_BRIDGE_MEDIA_SIZE) {
        return c.json({ error: `file too large: ${(stat.size / 1024 / 1024).toFixed(1)}MB (max 50MB)` }, 413);
      }
    } catch { return c.json({ error: "file not found" }, 404); }

    try {
      const manager = await ensureBridgeManager();
      if (!manager) return bridgeUnavailable(c, bridgeRef.getState?.() || {});
      if (typeof engine.registerSessionFile !== "function") {
        return c.json({ ok: false, error: "session file registry unavailable" }, 500);
      }
      if (typeof manager.sendMediaItem !== "function") {
        return c.json({ ok: false, error: "bridge media delivery unavailable" }, 500);
      }

      const sessionPath = typeof body.sessionPath === "string" && body.sessionPath.trim()
        ? body.sessionPath.trim()
        : buildBridgeManualSendSessionPath(agent.id, platform, chatId);
      const sessionFile = engine.registerSessionFile({
        sessionPath,
        filePath: realPath,
        label: typeof body.label === "string" && body.label.trim() ? body.label.trim() : path.basename(realPath),
        origin: "bridge_manual_send",
      });
      await manager.sendMediaItem(
        platform,
        chatId,
        { type: "session_file", fileId: sessionFile.id, sessionPath },
        agent.id,
      );
      return c.json({ ok: true, fileId: sessionFile.id });
    } catch (err) {
      return c.json(
        { ok: false, error: err.message },
        isUnsupportedMediaDeliveryError(err) ? 422 : 500,
      );
    }
  });

  /** 测试凭证（不启动轮询） */
  route.post("/bridge/test", async (c) => {
    const body = await safeJson(c);
    const { platform, credentials } = body;
    if (!platform || !credentials) {
      return c.json({ error: "platform and credentials required" }, 400);
    }

    if (!KNOWN_PLATFORMS.includes(platform)) {
      return c.json({ error: "unknown platform" }, 400);
    }
    const scopeDenied = denyWithoutScope(c, "bridge.manage");
    if (scopeDenied) return scopeDenied;
    const secretFields = collectSecretPatchPaths({ credentials }, bridgeSecretKeys(platform));
    const secretDenied = denySecretMutationWithoutScope(c, secretFields);
    if (secretDenied) return secretDenied;

    try {
      const usesMaskedCredentials = hasMaskedBridgeCredentials(platform, credentials);
      if (usesMaskedCredentials && !hasExplicitAgentId(c)) {
        return c.json({ error: "agentId is required when testing masked bridge credentials" }, 400);
      }
      const saved = usesMaskedCredentials
        ? resolveAgentStrict(engine, c).config?.bridge?.[platform] || {}
        : {};
      const effectiveCredentials = resolveBridgeCredentials(platform, credentials, saved);
      if (platform === "telegram") {
        const TelegramBot = (await import("node-telegram-bot-api")).default;
        const bot = new TelegramBot(effectiveCredentials.token, telegramBotOptions());
        const me = await bot.getMe();
        return c.json({ ok: true, info: { username: me.username, name: me.first_name } });
      } else if (platform === "feishu") {
        const resp = await fetch(FEISHU_TENANT_TOKEN_URL, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            app_id: effectiveCredentials.appId,
            app_secret: effectiveCredentials.appSecret,
          }),
          signal: AbortSignal.timeout(10_000),
        });
        const data = await resp.json();
        if (data.code === 0) {
          return c.json({
            ok: true,
            info: {
              msg: t("error.tokenSuccess"),
              ...feishuTestInfo({ credentialOk: true, response: resp, data }),
            },
          });
        }
        return c.json({
          ok: false,
          error: data.msg || t("error.verifyFailed"),
          info: feishuTestInfo({ credentialOk: false, response: resp, data }),
        });
      } else if (platform === "qq") {
        // v2 鉴权：appID + appSecret → access_token → /users/@me
        const tokenRes = await fetch("https://bots.qq.com/app/getAppAccessToken", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ appId: effectiveCredentials.appID, clientSecret: effectiveCredentials.appSecret }),
        });
        const tokenData = await tokenRes.json();
        if (!tokenData.access_token) {
          return c.json({ ok: false, error: tokenData.message || t("error.tokenFetchFailed") });
        }
        const meRes = await fetch("https://api.sgroup.qq.com/users/@me", {
          headers: { Authorization: `QQBot ${tokenData.access_token}` },
        });
        const me = await meRes.json();
        if (me.id) {
          return c.json({ ok: true, info: { username: me.username, name: me.username } });
        }
        return c.json({ ok: false, error: me.message || t("error.botInfoFailed") });
      }
      if (platform === "wechat") {
        // 用 getconfig 验证 token（不污染 cursor）
        const crypto = await import("node:crypto");
        const uin = Buffer.from(String(crypto.randomBytes(4).readUInt32BE(0)), "utf-8").toString("base64");
        const res = await fetch("https://ilinkai.weixin.qq.com/ilink/bot/getconfig", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "AuthorizationType": "ilink_bot_token",
            "Authorization": `Bearer ${effectiveCredentials.botToken}`,
            "X-WECHAT-UIN": uin,
          },
          body: JSON.stringify({ base_info: { channel_version: "1.0.0" } }),
          signal: AbortSignal.timeout(10_000),
        });
        const data = await res.json();
        if (data.ret && data.ret !== 0) {
          return c.json({ ok: false, error: data.errmsg || `errcode ${data.ret}` });
        }
        return c.json({ ok: true, info: { msg: "微信 iLink 连接成功" } });
      }
      return c.json({ ok: false, error: t("error.platformTestUnsupported") });
    } catch (err) {
      return c.json({ ok: false, error: err.message });
    }
  });

  /** 获取微信扫码登录二维码 */
  route.post("/bridge/wechat/qrcode", async (c) => {
    const { getWechatQrcode } = await import("../../lib/bridge/wechat-login.ts");
    return c.json(await getWechatQrcode());
  });

  /** 轮询微信扫码状态 */
  route.post("/bridge/wechat/qrcode-status", async (c) => {
    const body = await safeJson(c);
    const { qrcodeId } = body;
    const { pollWechatQrcodeStatus } = await import("../../lib/bridge/wechat-login.ts");
    return c.json(await pollWechatQrcodeStatus(qrcodeId));
  });

  return route;
}

function resolveBridgeCredentials(platform: any, credentials: any, existing: any): any {
  return resolveSecretPatch({
    patch: credentials,
    existing,
    secretKeys: bridgeSecretKeys(platform),
  });
}

function hasMaskedBridgeCredentials(platform: any, credentials: any) {
  const secretKeys = bridgeSecretKeys(platform);
  return secretKeys.some((key) => isMaskedSecretValue(credentials?.[key]));
}

function hasExplicitAgentId(c: any) {
  return Boolean(c.req.query("agentId") || c.req.param("agentId"));
}

function bridgeSecretKeys(platform: any): any {
  return platform === "feishu"
    ? ["appSecret"]
    : platform === "qq"
      ? ["appSecret", "token"]
      : platform === "wechat"
        ? ["botToken"]
        : ["token"];
}

function buildBridgeManualSendSessionPath(agentId: any, platform: any, chatId: any) {
  return `bridge:${agentId}:${platform}:${chatId}`;
}

function isUnsupportedMediaDeliveryError(err: any) {
  const message = String(err?.message || err || "");
  return /暂不支持|不支持|unsupported|不能直接消费|public_url fallback|cannot deliver|does not support media input mode/i.test(message);
}

function encodeRfc5987ValueChars(value: any) {
  return encodeURIComponent(value)
    .replace(/['()]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`)
    .replace(/\*/g, "%2A");
}

function isInlineBridgeMediaMime(mime: any) {
  const value = String(mime || "").toLowerCase();
  return value.startsWith("image/") || value.startsWith("video/");
}
