/**
 * WeChat 插件
 * 使用 @chnak/weixin-bot 实现微信对话
 *
 * 配置：
 * - forceLogin: 是否强制重新扫码登录
 * - qrcodeTerminal: 是否在终端渲染二维码 (默认 true)
 */

const { Plugin } = require('../src/core/plugin-base')
const { logger } = require('../src/utils/logger')
const log = logger.child('WeChat')
const {cleanResponse} =require('../src/utils')
const removeMarkdown = require('remove-markdown');
const { z } = require('zod')
const { WeixinBot } = require('@chnak/weixin-bot')
const fs = require('fs')
const path = require('path')

class WeixinPlugin extends Plugin {
  constructor(config = {}) {
    super()
    this.name = 'weixin'
    this.version = '1.0.0'
    this.description = '微信对话插件，使用微信网页账号进行对话'
    this.priority = 80
    // 默认不启用，需要在 plugins.json 中设置 enabled: true
    this.enabled = false
    this.path=`.agent/data`
    this.systemPrompt=`你是一个微信助手。

**重要:** 子Agent 匹配规则必须遵守：
- 根据【子 Agent 匹配表】，将任务委托给最匹配的子Agent处理
- 使用 subagent_call 工具并指定 agentName 来委托任务
- 只有当没有匹配的子Agent时，才直接调用工具

**命令执行规范：**
- 执行 npx skills add / npx skills remove / npx skills list 命令时，必须自动添加参数：-a openclaw -y
- 禁止添加 -g 参数
- 例如：npx skills add xxx 应该执行为 npx skills add xxx -a openclaw -y`

    this.config = {
      forceLogin: config.forceLogin || process.env.WEIXIN_FORCE_LOGIN === 'true',
      qrcodeTerminal: config.qrcodeTerminal !== false && process.env.WEIXIN_QRCODE_TERMINAL !== 'false',
      allowedUsers: config.allowedUsers || []
    }

    this._framework = null
    this._bot = null
    this._myUserId = null  // 机器人自己的 userId
    this._sessionPlugin = null
    this._sessionDeleteHandler = null
    this._sessionAgents = new Map()  // userId -> Agent
    this._qrcodeTerminal = null
    this._origStderrWrite = null
    this._initialized = false
  }

  install(framework) {
    this._framework = framework
    // 注册微信发送工具
    this._registerTools()
    return this
  }

  /**
   * 注册微信发送工具（发送给自己）
   */
  _registerTools() {
    // 发送文本消息给自己
    this.registerTool({
      name: 'weixin_send_message',
      description: '发送文本消息到微信（发给登录的账号）',
      inputSchema: z.object({
        message: z.string().describe('要发送的文本内容')
      }),
      execute: async (args) => {
        return this._sendMessage(args.message)
      }
    })

    // 发送图片给自己
    this.registerTool({
      name: 'weixin_send_image',
      description: '发送图片到微信（发给登录的账号）',
      inputSchema: z.object({
        imagePath: z.string().describe('本地图片文件路径')
      }),
      execute: async (args) => {
        return this._sendImage(args.imagePath)
      }
    })

    // 发送文件给自己
    this.registerTool({
      name: 'weixin_send_file',
      description: '发送文件到微信（发给登录的账号）',
      inputSchema: z.object({
        filePath: z.string().describe('本地文件路径'),
        fileName: z.string().optional().describe('文件名（可选，默认从路径推断）')
      }),
      execute: async (args) => {
        return this._sendFile(args.filePath, args.fileName)
      }
    })

    // 发送视频给自己
    this.registerTool({
      name: 'weixin_send_video',
      description: '发送视频到微信（发给登录的账号）',
      inputSchema: z.object({
        videoPath: z.string().describe('本地视频文件路径'),
        playLength: z.number().optional().describe('视频时长（秒）')
      }),
      execute: async (args) => {
        return this._sendVideo(args.videoPath, args.playLength)
      }
    })

    // 发送语音给自己
    this.registerTool({
      name: 'weixin_send_voice',
      description: '发送语音到微信（发给登录的账号，silk格式）',
      inputSchema: z.object({
        voicePath: z.string().describe('本地语音文件路径（silk格式）')
      }),
      execute: async (args) => {
        return this._sendVoice(args.voicePath)
      }
    })
  }

  /**
   * 发送图片给自己
   */
  async _sendImage(imagePath) {
    if (!this._bot) {
      return { error: '微信机器人未连接' }
    }
    if (!this._myUserId) {
      return { error: '未记录机器人用户ID' }
    }
    try {
      if (!fs.existsSync(imagePath)) {
        return { error: `文件不存在: ${imagePath}` }
      }
      await this._bot.sendImage(this._myUserId, imagePath)
      // log.info(` 图片发送成功: ${path.basename(imagePath)}`)
      return { success: true, message: '图片发送成功' }
    } catch (err) {
      log.error(` 图片发送失败: ${err.message}`)
      return { error: err.message }
    }
  }

  /**
   * 发送文件给自己
   */
  async _sendFile(filePath, fileName) {
    if (!this._bot) {
      return { error: '微信机器人未连接' }
    }
    if (!this._myUserId) {
      return { error: '未记录机器人用户ID' }
    }
    try {
      if (!fs.existsSync(filePath)) {
        return { error: `文件不存在: ${filePath}` }
      }
      await this._bot.sendFile(this._myUserId, filePath, fileName)
      // log.info(` 文件发送成功: ${fileName || path.basename(filePath)}`)
      return { success: true, message: '文件发送成功' }
    } catch (err) {
      log.error(` 文件发送失败: ${err.message}`)
      return { error: err.message }
    }
  }

  /**
   * 发送视频给自己
   */
  async _sendVideo(videoPath, playLength) {
    if (!this._bot) {
      return { error: '微信机器人未连接' }
    }
    if (!this._myUserId) {
      return { error: '未记录机器人用户ID' }
    }
    try {
      if (!fs.existsSync(videoPath)) {
        return { error: `文件不存在: ${videoPath}` }
      }
      const opts = playLength ? { playLength } : {}
      await this._bot.sendVideo(this._myUserId, videoPath, opts)
      // log.info(` 视频发送成功: ${path.basename(videoPath)}`)
      return { success: true, message: '视频发送成功' }
    } catch (err) {
      log.error(` 视频发送失败: ${err.message}`)
      return { error: err.message }
    }
  }

  /**
   * 发送语音给自己
   */
  async _sendVoice(voicePath) {
    if (!this._bot) {
      return { error: '微信机器人未连接' }
    }
    if (!this._myUserId) {
      return { error: '未记录机器人用户ID' }
    }
    try {
      if (!fs.existsSync(voicePath)) {
        return { error: `文件不存在: ${voicePath}` }
      }
      await this._bot.sendVoice(this._myUserId, voicePath)
      // log.info(` 语音发送成功: ${path.basename(voicePath)}`)
      return { success: true, message: '语音发送成功' }
    } catch (err) {
      log.error(` 语音发送失败: ${err.message}`)
      return { error: err.message }
    }
  }

  /**
   * 发送文本消息给自己
   */
  async _sendMessage(message) {
    if (!this._bot) {
      return { error: '微信机器人未连接' }
    }
    if (!this._myUserId) {
      return { error: '未记录机器人用户ID' }
    }
    try {
      await this._bot.send(this._myUserId, message)
      return { success: true, message: '消息发送成功' }
    } catch (err) {
      log.error(` 消息发送失败: ${err.message}`)
      return { error: err.message }
    }
  }

  async start(framework) {
    // 防止重复初始化
    if (this._initialized) return this
    this._initialized = true

    // 获取 SessionPlugin 引用
    this._sessionPlugin = framework.pluginManager.get('session')

    // 监听 SessionPlugin 的会话删除事件
    if (this._sessionPlugin) {
      this._sessionDeleteHandler = (sessionId) => {
        // 只处理 weixin 会话的删除
        if (sessionId.startsWith('weixin_')) {
          // log.info(` Session deleted: ${sessionId}`)
        }
      }
      this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
    }

    // 监听定时提醒事件
    if (this._framework) {
      this._framework.on('scheduler:reminder', async (data) => {
        // log.info(' Received scheduler reminder:', data)
        await this._handleScheduledReminder(data)
      })

      // 监听 webhook 事件
      this._framework.on('webhook:received', async (data) => {
        // log.info(' Received webhook event:', data)
        await this._handleWebhookNotification(data)
      })

      // 监听统一通知事件
      this._framework.on('notification', async (data) => {
        // log.info(' Received notification:', data)
        await this._handleNotification(data)
      })
    }

    // 异步初始化 Bot
    this._initBotAsync().catch(err => {
      log.error(' Failed to initialize bot:', err.message)
    })
    return this
  }

  async _initBotAsync() {

    // 如果启用终端二维码渲染
    if (this.config.qrcodeTerminal) {
      try {
        this._qrcodeTerminal = require('qrcode-terminal')
        this._interceptQRCode()
      } catch (err) {
        log.warn(' qrcode-terminal not installed:', err.message)
      }
    }

    this._bot = new WeixinBot({
      tokenPath:`${this.path}/${this.name}.json`,
      onError: (err) => {
        log.error(' Error:', err.message)
      },
    })

    const loginOptions = { force: this.config.forceLogin }
    // log.info('', this.config.forceLogin ? '强制重新扫码登录...' : '正在登录（已有凭证则自动跳过扫码）...')

    const creds = await this._bot.login(loginOptions)
    // log.info(' 登录成功 — Bot ID:', creds.accountId)
    // log.info(' 关联用户:', creds.userId)
    // log.info(' API 地址:', creds.baseUrl)

    // 记录机器人自己的 userId（用于发送媒体）
    this._myUserId = creds.userId
    // log.info(' 已记录机器人 userId:', this._myUserId)

    // 注册消息处理
    this._bot.onMessage(async (msg) => {
      await this._handleMessage(msg)
    })

    // 启动Bot
    await this._bot.run()
    // log.info(' 开始接收微信消息')
  }

  /**
   * 拦截 SDK 的 stderr 输出，渲染二维码到终端
   */
  _interceptQRCode() {
    if (!this._qrcodeTerminal) return

    this._origStderrWrite = process.stderr.write.bind(process.stderr)
    process.stderr.write = ((chunk, ...args) => {
      const str = typeof chunk === 'string' ? chunk : chunk.toString()
      // 检测到登录 URL，渲染二维码
      if (str.startsWith('https://') && str.includes('qrcode=')) {
        const url = str.trim()
        this._qrcodeTerminal.generate(url, { small: true }, (qr) => {
          this._origStderrWrite(qr + '\n')
        })
      }
      return this._origStderrWrite(chunk, ...args)
    })
  }

  /**
   * 获取主Agent
   */
  _getMainAgent() {
    if (this._framework._mainAgent) {
      return this._framework._mainAgent
    }
    const agents = this._framework._agents || []
    return agents.length > 0 ? agents[agents.length - 1] : null
  }

  /**
   * 获取或创建会话Agent
   * 使用 SessionPlugin 统一管理会话历史
   */
  _getSessionAgent(userId) {
    // 检查缓存
    if (this._sessionAgents.has(userId)) {
      const agent = this._sessionAgents.get(userId)
      // log.info(' Reusing cached session agent for userId:', userId)
      return { agent, sessionId: `weixin_${userId}` }
    }

    // 创建新 agent - 和 CLI 一样使用 createAgent
    const agent = this._framework.createAgent({
      name: `weixin_${userId}`,
      systemPrompt: this.systemPrompt,
      sharedPrompt: `工作目录: {{WORK_DIR}}`,
      metadata: { WORK_DIR: process.cwd() }
    })
    this._sessionAgents.set(userId, agent)
    // log.info(' Created new session agent for userId:', userId)

    // 使用 SessionPlugin 管理会话历史
    if (this._sessionPlugin) {
      const sessionId = `weixin_${userId}`
      this._sessionPlugin.getOrCreateSession(sessionId, {
        metadata: { platform: 'weixin', userId }
      })
    }

    // log.info(` Session ready for user: ${userId}`)
    return { agent, sessionId: `weixin_${userId}` }
  }

  /**
   * 处理消息
   */
  async _handleMessage(msg) {
    if (!msg || !msg.userId) return

    const userId = msg.userId
    // 从 SessionPlugin 获取历史消息数量
    let messageCount = 0
    if (this._sessionPlugin) {
      const session = this._sessionPlugin.getSession(`weixin_${userId}`)
      messageCount = session?.messages?.length || 0
    }

    //log.info(` #${messageCount + 1} | 类型: ${msg.type} | 用户: ${userId}`)

    // 处理不同类型的消息
    switch (msg.type) {
      case 'text':
        // log.info(` 内容: ${msg.text}`)
        if (msg.text) {
          await this._processChat(userId, msg.text.trim(), msg)
        }
        break

      case 'image':
        // log.info(` 收到图片消息`)
        await this._processMediaChat(userId, '[用户发送了图片]', msg)
        break

      case 'file':
        // log.info(` 收到文件消息: ${msg.fileName || 'unknown'}`)
        await this._processMediaChat(userId, `[用户发送了文件: ${msg.fileName || 'unknown'}]`, msg)
        break

      case 'video':
        // log.info(` 收到视频消息`)
        await this._processMediaChat(userId, '[用户发送了视频]', msg)
        break

      case 'voice':
        // log.info(` 收到语音消息`)
        await this._processMediaChat(userId, '[用户发送了语音消息]', msg)
        break

      default:
        // log.info(` 不支持的消息类型: ${msg.type}`)
        if (msg.text) {
          await this._processChat(userId, msg.text.trim(), msg)
        }
    }
  }

  /**
   * 处理媒体消息（图片/文件/视频/语音）
   */
  async _processMediaChat(userId, text, originalMsg) {
    const sessionInfo = this._getSessionAgent(userId)
    if (!sessionInfo) {
      log.error(' No session agent available')
      return
    }

    const { agent, sessionId } = sessionInfo

    // 发送正在输入状态
    try {
      await this._bot.sendTyping(userId)
    } catch { /* typing 失败不影响回复 */ }

    await new Promise((resolve) => setTimeout(resolve, 1000))

    try {
      // 使用 chatStream 保持和 CLI 一致的行为
      
      let fullResponse = '';
      for await (const chunk of agent.chatStream(text, { sessionId })) {
        if (chunk.type === 'text') {
          fullResponse += chunk.text;
        }
      }
      const response = cleanResponse(fullResponse);

      if (response) {
        await this._sendMessageBatch(originalMsg, userId, response, true)
      }
    } catch (err) {
      log.error(' Media chat error:', err)
      await this._sendMessageBatch(originalMsg, userId, `发生错误：${err.message}`, true)
    }
  }

  /**
   * 处理对话
   */
  async _processChat(userId, text, originalMsg) {
    const sessionInfo = this._getSessionAgent(userId)
    if (!sessionInfo) {
      log.error(' No session agent available')
      return
    }

    const { agent, sessionId } = sessionInfo

    // 使用 SessionPlugin 添加用户消息到历史
    // if (this._sessionPlugin) {
    //   this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
    // }

    // 发送正在输入状态
    try {
      await this._bot.sendTyping(userId)
    } catch { /* typing 失败不影响回复 */ }

    await new Promise((resolve) => setTimeout(resolve, 1000))

    try {
      // 使用 chatStream 保持和 CLI 一致的行为
      let fullResponse = '';
      for await (const chunk of agent.chatStream(text, { sessionId })) {
        if (chunk.type === 'text') {
          fullResponse += chunk.text;
        }
      }
      const response = cleanResponse(fullResponse);

      // 发送回复（超过500字自动分批）
      if (response) {
        await this._sendMessageBatch(originalMsg, userId, response, true)
      } else {
        await this._sendMessageBatch(originalMsg, userId, '抱歉，我没有收到有效的回复。', true)
      }

    } catch (err) {
      log.error(' Chat error:', err.message)
      await this._sendMessageBatch(originalMsg, userId, `发生错误：${err.message}`, true)
    }
  }

  /**
   * 权限检查
   */
  _checkPermission(userId) {
    if (!this.config.allowedUsers || this.config.allowedUsers.length === 0) {
      return true
    }
    return this.config.allowedUsers.includes(userId)
  }

  /**
   * 发送消息（超过500字自动分批）
   * @param {Object} originalMsg - 原始消息对象（用于reply）
   * @param {string} userId - 用户ID（用于sendText）
   * @param {string} text - 要发送的文本
   * @param {boolean} useReply - 是否使用reply方式
   */
  async _sendMessageBatch(originalMsg, userId, text, useReply = true) {
    const MAX_LEN = 500
    text=removeMarkdown(text)
    if (!text || text.length <= MAX_LEN) {
      if (useReply && originalMsg) {
        await this._bot.reply(originalMsg, text)
      } else {
        await this._bot.sendText(userId, text)
      }
      return
    }

    // 分批发送
    const chunks = []
    for (let i = 0; i < text.length; i += MAX_LEN) {
      chunks.push(text.slice(i, i + MAX_LEN))
    }

    // log.info(` Message too long (${text.length}), splitting into ${chunks.length} parts`)

    for (let i = 0; i < chunks.length; i++) {
      const chunk = `[${i + 1}/${chunks.length}]\n${chunks[i]}`
      if (useReply && originalMsg) {
        await this._bot.reply(originalMsg, chunk)
      } else {
        await this._bot.sendText(userId, chunk)
      }
      // 批次间隔，避免发送太快
      if (i < chunks.length - 1) {
        await new Promise(r => setTimeout(r, 300))
      }
    }
  }

  /**
   * 清除会话
   */
  _clearSession(userId) {
    // 清除 SessionPlugin 中的会话（会触发 session:deleted 事件）
    if (this._sessionPlugin) {
      const sessionId = `weixin_${userId}`
      this._sessionPlugin.deleteSession(sessionId)
    }
  }

  /**
   * 处理定时提醒
   */
  async _handleScheduledReminder(data) {
    const { taskName, message, sessionId } = data

    if (!this._bot) {
      log.warn(' Bot not ready, cannot send reminder')
      return
    }

    // 构建提醒消息
    const reminderText = `🔔 [${taskName}]\n\n${message}`

    // 如果有 sessionId 是 weixin 类型的，发送到对应用户
    if (sessionId && sessionId.startsWith('weixin_')) {
      const userId = sessionId.replace('weixin_', '')
      try {
        await this._sendMessageBatch(null, userId, reminderText, false)
        // log.info(` Reminder sent to user ${userId}`)
      } catch (err) {
        log.error(` Failed to send reminder:`, err.message)
      }
      return
    }

    // 其他情况（包括 null 或其他 sessionId），发送到最近的 WeChat 会话
    if (this._sessionPlugin) {
      const allSessions = this._sessionPlugin.listSessions()
      const weixinSessions = allSessions
        .filter(s => s.id.startsWith('weixin_'))
        .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())

      if (weixinSessions.length > 0) {
        const userId = weixinSessions[0].id.replace('weixin_', '')
        try {
          await this._sendMessageBatch(null, userId, reminderText, false)
          // log.info(` Reminder sent to recent user ${userId}`)
        } catch (err) {
          log.error(` Failed to send reminder:`, err.message)
        }
      } else {
        log.warn(' No WeChat session found to send reminder')
      }
    }
  }

  /**
   * 处理 webhook 通知
   */
  async _handleWebhookNotification(data) {
    const { data: webhookData, response, sessionId } = data

    if (!this._bot) {
      log.warn(' Bot not ready, cannot send webhook notification')
      return
    }

    // 只处理 weixin 相关的 session
    if (!sessionId || !sessionId.startsWith('weixin_')) {
      return
    }

    const userId = sessionId.replace('weixin_', '')
    const notificationText = `📥 [Webhook 接收]\n\n路径: ${webhookData.path}\n方法: ${webhookData.method}\n\n处理结果: ${response || '处理中...'}`

    try {
      await this._sendMessageBatch(null, userId, notificationText, false)
      // log.info(` Webhook notification sent to user ${userId}`)
    } catch (err) {
      log.error(` Failed to send webhook notification:`, err.message)
    }
  }

  /**
   * 处理统一通知
   */
  async _handleNotification(data) {
    const { title, message, source, level, sessionId } = data

    if (!this._bot) {
      log.warn(' Bot not ready, cannot send notification')
      return
    }

    // 确定用户ID
    let userId = null
    let effectiveSessionId = sessionId

    // 如果没有 sessionId，尝试从执行上下文获取
    if (!effectiveSessionId) {
      const ctx = this._framework.getExecutionContext()
      if (ctx?.sessionId) {
        effectiveSessionId = ctx.sessionId
      }
    }

    if (effectiveSessionId && effectiveSessionId.startsWith('weixin_')) {
      userId = effectiveSessionId.replace('weixin_', '')
    } else if (this._sessionPlugin) {
      // 获取最近的 weixin 会话
      const sessions = this._sessionPlugin.listSessions()
        .filter(s => s.id.startsWith('weixin_'))
        .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
      if (sessions.length > 0) {
        userId = sessions[0].id.replace('weixin_', '')
      }
    }

    if (!userId) {
      log.warn(' No weixin session found for notification')
      return
    }

    // 格式化通知消息
    const levelEmoji = {
      info: 'ℹ️',
      warning: '⚠️',
      success: '✅',
      error: '❌'
    }
    const emoji = levelEmoji[level] || 'ℹ️'
    const notificationText = `${emoji} [${source}] ${title}\n\n${message}`

    try {
      await this._sendMessageBatch(null, userId, notificationText, false)
      // log.info(` Notification sent to user ${userId}`)
    } catch (err) {
      log.error(` Failed to send notification:`, err.message)
    }
  }

  /**
   * 获取插件状态
   */
  getStatus() {
    // 从 SessionPlugin 获取 WeChat 相关会话
    let sessions = []
    if (this._sessionPlugin) {
      const allSessions = this._sessionPlugin.listSessions()
      sessions = allSessions
        .filter(s => s.id.startsWith('weixin_'))
        .map(s => ({
          userId: s.id.replace('weixin_', ''),
          historyLength: s.messageCount,
          lastActive: s.lastActive
        }))
    }

    return {
      connected: !!this._bot,
      sessionCount: sessions.length,
      sessions,
      config: {
        forceLogin: this.config.forceLogin,
        qrcodeTerminal: this.config.qrcodeTerminal
      }
    }
  }

  /**
   * 停止 Bot
   */
  stopBot() {
    if (this._bot) {
      this._bot.stop()
      this._bot = null
      // log.info(' Bot stopped')
    }
  }

  reload(framework) {
    this._framework = framework
    this._initialized = false
    this.stopBot()
    this.start(framework)
  }

  uninstall(framework) {
    // 销毁所有 session agents
    for (const agent of this._sessionAgents.values()) {
      agent.destroy()
    }
    this._sessionAgents.clear()

    this.stopBot()
    if (this._sessionPlugin && this._sessionDeleteHandler) {
      this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
      this._sessionDeleteHandler = null
    }
    this._sessionPlugin = null
    this._framework = null
    // 恢复 stderr
    if (this._origStderrWrite) {
      process.stderr.write = this._origStderrWrite
    }
  }
}

module.exports = WeixinPlugin