/**
 * 飞书插件
 * 使用 @larksuiteoapi/node-sdk 的 WebSocket 长连接模式
 *
 * 配置：
 * - appId: 飞书应用 ID
 * - appSecret: 飞书应用密钥
 * - allowedUsers: 允许的用户 openId 数组
 */

const { Plugin } = require('../src/core/plugin-base')
const { logger } = require('../src/utils/logger')
const log = logger.child('Feishu')
const {cleanResponse} =require('../src/utils')
const removeMarkdown = require('remove-markdown');
class FeishuPlugin extends Plugin {
  constructor(config = {}) {
    super()
    this.name = 'feishu'
    this.version = '1.1.0'
    this.description = '飞书对话插件，使用 WebSocket 长连接接收消息'
    this.priority = 80
    this.enabled = false
    this.systemPrompt = `你是一个飞书助手。回复内容不要使用markdown格式文本。

**重要:** 子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 = {
      appId: config.appId || process.env.FEISHU_APP_ID,
      appSecret: config.appSecret || process.env.FEISHU_APP_SECRET,
      allowedUsers: config.allowedUsers || []
    }

    this._framework = null
    this._client = null
    this._wsClient = null
    this._sessionPlugin = null
    this._sessionDeleteHandler = null
    this._sessionAgents = new Map()
    this._initialized = false
    this._processedMessages = new Set()
    this._messageCleanupInterval = null
    this._processingLock = new Map()
  }

  install(framework) {
    this._framework = framework
    return this
  }

  start(framework) {
    if (this._initialized) return this
    this._initialized = true

    if (!this.config.appId || !this.config.appSecret) {
      log.warn(' No appId or appSecret.')
      return this
    }

    this._framework = framework
    this._sessionPlugin = framework.pluginManager.get('session')

    if (this._sessionPlugin) {
      this._sessionDeleteHandler = (sessionId) => {
        if (sessionId.startsWith('feishu_')) {
          log.info(` Session deleted: ${sessionId}`)
        }
      }
      this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
    }

    this._initClient()
    return this
  }

  _initClient() {
    try {
      const { Client, WSClient, EventDispatcher } = require('@larksuiteoapi/node-sdk')

      this._client = new Client({
        appId: this.config.appId,
        appSecret: this.config.appSecret,
        logger: console
      })

      this._wsClient = new WSClient({
        appId: this.config.appId,
        appSecret: this.config.appSecret,
        logger: console
      })

      const eventDispatcher = new EventDispatcher({}).register({
        'im.message.receive_v1': async (data) => {
          await this._handleMessage(data)
        }
      })

      this._wsClient.start({ eventDispatcher })

      this._messageCleanupInterval = setInterval(() => {
        this._processedMessages.clear()
      }, 60000)

      if (this._framework) {
        this._framework.on('scheduler:reminder', async (data) => {
          await this._handleScheduledReminder(data)
        })

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

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

      log.info(' WebSocket client started')
    } catch (err) {
      log.error(' Failed to initialize client:', err.message, err.stack)
    }
  }

  async _handleMessage(data) {
    try {
      if (!data || !data.message || Object.keys(data.message).length === 0) {
        return
      }

      const message = data.message
      const chatId = message.chat_id
      const messageId = message.message_id
      const openId = message.sender?.sender_id?.open_id || message.sender?.open_id || message.open_id || chatId
      const messageType = message.message_type
      let content = {}

      try {
        content = message.content ? JSON.parse(message.content) : {}
      } catch (e) {
        return
      }

      if (messageId && this._processedMessages.has(messageId)) {
        return
      }
      if (messageId) this._processedMessages.add(messageId)

      if (messageType !== 'text') return

      const text = content.text?.trim()
      if (!text) return

      if (!this._checkPermission(openId)) return

      if (text.startsWith('/')) {
        await this._handleCommand(openId, text, message)
        return
      }

      if (this._processingLock.get(openId)) return
      this._processingLock.set(openId, true)

      try {
        await this._processChat(openId, text, message)
      } finally {
        this._processingLock.set(openId, false)
      }
    } catch (err) {
      log.error(' Error handling message:', err.message)
    }
  }

  async _handleCommand(openId, text, originalMsg) {
    const parts = text.split(' ')
    const command = parts[0].substring(1)
    const args = parts.slice(1).join(' ')

    switch (command.toLowerCase()) {
      case 'start':
      case 'help':
        await this._sendMessage(openId,
          '👋 欢迎使用 AI 助手！\n\n直接发送消息即可与我对话。\n\n可用命令：\n/start - 显示帮助\n/clear - 清除对话历史\n/history - 查看历史消息数',
          originalMsg)
        break
      case 'clear':
        this._clearSession(openId)
        await this._sendMessage(openId, '✅ 对话历史已清除', originalMsg)
        break
      case 'history':
        if (this._sessionPlugin) {
          const session = this._sessionPlugin.getSession(`feishu_${openId}`)
          const sessions = this._sessionPlugin.listSessions().filter(s => s.id.startsWith('feishu_'))
          await this._sendMessage(openId,
            `📊 当前状态\n\n会话数：${sessions.length}\n历史消息：${session?.messages?.length || 0}\n最后活跃：${session?.lastActive?.toLocaleString() || '无'}`,
            originalMsg)
        } else {
          await this._sendMessage(openId, '❌ 会话服务不可用', originalMsg)
        }
        break
      default:
        await this._processChat(openId, text, originalMsg)
    }
  }

  _getSessionAgent(openId) {
    if (this._sessionAgents.has(openId)) {
      return { agent: this._sessionAgents.get(openId), sessionId: `feishu_${openId}` }
    }

    const agent = this._framework.createSessionAgent(`feishu_${openId}`, {
      systemPrompt: this.systemPrompt,
      sharedPrompt: `工作目录: {{WORK_DIR}}`,
      metadata: { WORK_DIR: process.cwd() }
    })
    this._sessionAgents.set(openId, agent)

    if (this._sessionPlugin) {
      this._sessionPlugin.getOrCreateSession(`feishu_${openId}`, {
        metadata: { platform: 'feishu', openId }
      })
    }

    return { agent, sessionId: `feishu_${openId}` }
  }

  async _handleScheduledReminder(data) {
    const { taskName, message, sessionId } = data
    const reminderText = `🔔 [${taskName}]\n\n${message}`

    if (sessionId && sessionId.startsWith('feishu_')) {
      const openId = sessionId.replace('feishu_', '')
      try {
        await this._sendTextMessage(openId, reminderText)
      } catch (err) {
        log.error(` Failed to send reminder:`, err.message)
      }
      return
    }

    if (this._sessionPlugin) {
      const sessions = this._sessionPlugin.listSessions()
        .filter(s => s.id.startsWith('feishu_'))
        .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())

      if (sessions.length > 0) {
        const openId = sessions[0].id.replace('feishu_', '')
        try {
          await this._sendTextMessage(openId, reminderText)
        } catch (err) {
          log.error(` Failed to send reminder:`, err.message)
        }
      }
    }
  }

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

    if (!sessionId || !sessionId.startsWith('feishu_')) {
      return
    }

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

    try {
      await this._sendTextMessage(openId, notificationText)
      log.info(` Webhook notification sent to ${openId}`)
    } catch (err) {
      log.error(` Failed to send webhook notification:`, err.message)
    }
  }

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

    // 确定 openId
    let openId = null
    let effectiveSessionId = sessionId

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

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

    if (!openId) {
      log.warn(' No feishu 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._sendTextMessage(openId, notificationText)
      log.info(` Notification sent to ${openId}`)
    } catch (err) {
      log.error(` Failed to send notification:`, err.message)
    }
  }

  async _processChat(openId, text, originalMsg) {
    const sessionInfo = this._getSessionAgent(openId)
    if (!sessionInfo) return

    const { agent, sessionId } = sessionInfo

    // if (this._sessionPlugin) {
    //   this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
    // }

    try {
      // 使用非流式响应
      const result = await agent.chat(text, { sessionId })
      const fullResponse = cleanResponse(result.message || '')

      // if (this._sessionPlugin) {
      //   this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
      // }

      if (fullResponse) {
        await this._sendMessage(openId, fullResponse, originalMsg)
      } else {
        await this._sendMessage(openId, '抱歉，我没有收到有效的回复。', originalMsg)
      }
    } catch (err) {
      log.error(' Chat error:', err)
      await this._sendMessage(openId, `发生错误：${err.message}`, originalMsg)
    }
  }

  async _sendTextMessage(openId, text) {
    if (!this._client) return
    try {
      await this._client.im.message.create({
        params: { receive_id_type: 'chat_id' },
        data: {
          receive_id: openId,
          content: JSON.stringify({ text }),
          msg_type: 'text'
        }
      })
    } catch (err) {
      log.error(' Failed to send text message:', err.message)
      throw err
    }
  }

  async _sendMessage(openId, text, originalMsg) {
    if (!this._client) return
    text=removeMarkdown(text)
    try {
      const chatId = originalMsg?.chat_id || originalMsg?.message?.chat_id
      if (!chatId) return

      await this._client.im.message.create({
        params: { receive_id_type: 'chat_id' },
        data: {
          receive_id: chatId,
          content: JSON.stringify({ text }),
          msg_type: 'text'
        }
      })
    } catch (err) {
      log.error(' Failed to send message:', err.message)
    }
  }

  _checkPermission(openId) {
    return this.config.allowedUsers.length === 0 || this.config.allowedUsers.includes(openId)
  }

  _clearSession(openId) {
    if (this._sessionPlugin) {
      this._sessionPlugin.deleteSession(`feishu_${openId}`)
    }
  }

  getStatus() {
    let sessions = []
    if (this._sessionPlugin) {
      sessions = this._sessionPlugin.listSessions()
        .filter(s => s.id.startsWith('feishu_'))
        .map(s => ({
          openId: s.id.replace('feishu_', ''),
          historyLength: s.messageCount,
          lastActive: s.lastActive
        }))
    }
    return {
      connected: !!this._wsClient,
      sessionCount: sessions.length,
      sessions,
      config: {
        appId: this.config.appId ? `${this.config.appId.substring(0, 10)}...` : null,
        allowedUsersCount: this.config.allowedUsers.length
      }
    }
  }

  stopClient() {
    if (this._wsClient) {
      try { this._wsClient.close() } catch (e) { /* ignore */ }
      this._wsClient = null
      this._client = null
      log.info(' Client stopped')
    }
  }

  stop() {
    this.stopClient()
  }

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

  uninstall() {
    for (const agent of this._sessionAgents.values()) {
      agent.destroy()
    }
    this._sessionAgents.clear()

    if (this._messageCleanupInterval) {
      clearInterval(this._messageCleanupInterval)
      this._messageCleanupInterval = null
    }
    this._processedMessages.clear()

    this.stopClient()
    if (this._sessionPlugin && this._sessionDeleteHandler) {
      this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
      this._sessionDeleteHandler = null
    }
    this._sessionPlugin = null
    this._framework = null
  }
}

module.exports = FeishuPlugin
