/**
 * Web 服务插件
 * 支持 HTTP 服务、路由注册、Webhook（自动生成 /webhook/{id} 链接）
 */

const { Plugin } = require('../src/core/plugin-base')
const { logger } = require('../src/utils/logger')
const { runInSandbox } = require('../src/utils/sandbox')
const log = logger.child('Web')
const { z } = require('zod')
const { serve } = require('@hono/node-server')
const { Hono } = require('hono')
const fs = require('fs')
const path = require('path')

// ============================================================================
// WebStore - 持久化 Web 配置到 .agent/data/web/
// ============================================================================
class WebStore {
  constructor(persistencePath) {
    this._persistencePath = persistencePath
    this._ensureDir()
  }

  _ensureDir() {
    if (!fs.existsSync(this._persistencePath)) {
      fs.mkdirSync(this._persistencePath, { recursive: true })
    }
  }

  _getConfigPath() {
    return path.join(this._persistencePath, 'web-config.json')
  }

  saveConfig(data) {
    try {
      fs.writeFileSync(this._getConfigPath(), JSON.stringify(data, null, 2))
    } catch (err) {
      log.error(' 保存 Web 配置失败:', err.message)
    }
  }

  loadConfig() {
    try {
      const filePath = this._getConfigPath()
      if (fs.existsSync(filePath)) {
        return JSON.parse(fs.readFileSync(filePath, 'utf-8'))
      }
    } catch (err) {
      log.error(' 加载 Web 配置失败:', err.message)
    }
    return null
  }
}

class WebPlugin extends Plugin {
  constructor(config = {}) {
    super()
    this.name = 'web'
    this.version = '3.1.0'
    this.description = 'Web 服务插件，支持 HTTP 服务、路由注册、Webhook'
    this.priority = 50

    this.system = true 

    // 服务器配置
    this._port = process.env.WEB_PORT || 3000
    this._host = process.env.WEB_HOST || '127.0.0.1'
    this._baseUrl = process.env.WEB_BASE_URL || null  // 公网可访问的域名

    // 运行时状态
    this._server = null
    this._app = null
    this._framework = null

    this.tools = {}

    // 数据存储（始终保持原始类型）
    this._routes = []           // 路由列表
    this._webhooks = new Map()  // webhook Map: id -> {id, path, prompt, sessionId}
    this._statics = []          // 静态文件夹列表

    // 持久化存储
    this._webStore = null
    this._persistencePath = config.persistencePath || '.agent/data/web'
  }

  // ==================== 生命周期 ====================

  install(framework) {
    this._framework = framework
    this._registerTools()

    // 初始化持久化存储
    this._webStore = new WebStore(this._persistencePath)

    // 加载已保存的配置
    this._loadPersistedConfig()

    // 将 WEB_BASE_URL 注入到 framework 的元数据，供所有 agent 使用
    if (this._baseUrl && framework._mainAgent) {
      framework._mainAgent.setMetadata('WEB_BASE_URL', this._baseUrl)
    }

    return this
  }

  start() {
    return this
  }

  reload(framework) {
    this._framework = framework

    // 重新初始化存储并加载配置
    this._webStore = new WebStore(this._persistencePath)
    this._loadPersistedConfig()

    // 重新注入 WEB_BASE_URL
    if (this._baseUrl && framework._mainAgent) {
      framework._mainAgent.setMetadata('WEB_BASE_URL', this._baseUrl)
    }
  }

  /**
   * 加载持久化的配置并恢复路由/webhook/静态资源
   */
  _loadPersistedConfig() {
    if (!this._webStore) return

    const config = this._webStore.loadConfig()
    if (!config) return

    log.info(` 加载 Web 配置...`)

    let hasRoutes = false
    let hasWebhooks = false
    let hasStatics = false

    // 恢复路由
    if (config.routes && Array.isArray(config.routes)) {
      for (const route of config.routes) {
        if (route.method && route.path && route.handler) {
          this._routes.push({
            method: route.method,
            path: route.path,
            handler: route.handler,
            description: route.description || ''
          })
          hasRoutes = true
          log.info(` 恢复路由: ${route.method} ${route.path}`)
        }
      }
    }

    // 恢复 Webhooks
    if (config.webhooks && Array.isArray(config.webhooks)) {
      for (const webhook of config.webhooks) {
        if (webhook.id && webhook.path) {
          this._webhooks.set(webhook.path, {
            id: webhook.id,
            path: webhook.path,
            prompt: webhook.prompt || '处理以下 webhook 数据，返回适当的响应：',
            awaitResponse: webhook.awaitResponse || false
          })
          hasWebhooks = true
          log.info(` 恢复 Webhook: ${webhook.path}`)
        }
      }
    }

    // 恢复静态资源
    if (config.statics && Array.isArray(config.statics)) {
      for (const staticItem of config.statics) {
        if (staticItem.urlPath && staticItem.folder) {
          this._statics.push({
            urlPath: staticItem.urlPath,
            folder: staticItem.folder,
            options: staticItem.options || { dotfiles: 'ignore', index: 'index.html' }
          })
          hasStatics = true
          log.info(` 恢复静态资源: ${staticItem.urlPath} -> ${staticItem.folder}`)
        }
      }
    }

    // 如果有恢复的路由/webhook/静态资源，自动启动服务器
    if ((hasRoutes || hasWebhooks || hasStatics) && !this._server) {
      log.info(` 恢复的 Web 配置需要启动服务器...`)
      this._startServer().catch(err => {
        log.error(` 自动启动服务器失败:`, err.message)
      })
    }
  }

  /**
   * 保存当前配置到持久化存储
   */
  _saveConfig() {
    if (!this._webStore) return

    const config = {
      routes: this._routes.map(r => ({
        method: r.method,
        path: r.path,
        handler: r.handler,
        description: r.description
      })),
      webhooks: Array.from(this._webhooks.values()).map(w => ({
        id: w.id,
        path: w.path,
        prompt: w.prompt,
        awaitResponse: w.awaitResponse
      })),
      statics: this._statics.map(s => ({
        urlPath: s.urlPath,
        folder: s.folder,
        options: s.options
      }))
    }

    this._webStore.saveConfig(config)
  }

  uninstall() {
    this._stopServer()
    this._framework = null
  }

  // ==================== 工具注册 ====================

  _registerTools() {
    // 启动 Web 服务
    this.tools.web_start = {
      name: 'web_start',
      description: '启动 Web 服务',
      inputSchema: z.object({
        port: z.number().optional().describe('端口号，默认 3000'),
        host: z.string().optional().describe('主机地址，默认 0.0.0.0')
      }),
      execute: async (args) => this._startServer(args.port, args.host)
    }

    // 停止 Web 服务
    this.tools.web_stop = {
      name: 'web_stop',
      description: '停止 Web 服务',
      inputSchema: z.object({}),
      execute: async () => this._stopServer()
    }

    // 注册 HTTP 路由
    this.tools.web_register_route = {
      name: 'web_register_route',
      description: '注册 HTTP 路由',
      inputSchema: z.object({
        method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).describe('HTTP 方法'),
        path: z.string().describe('路由路径，如 /api/user'),
        handler: z.string().describe(
          '处理逻辑，JavaScript 代码字符串，必须用 return 返回内容。' +
          '优先使用 tools.{toolName}(args) 调用工具获取真实数据。' +
          '可用变量：context.params, context.query, context.body, tools。' +
          '示例：return await tools.get_user({ id: context.params.id })'
        ),
        description: z.string().optional().describe('路由描述')
      }),
      execute: async (args) => this._registerRoute(args.method, args.path, args.handler, args.description)
    }

    // 注册 Webhook（自动生成 /webhook/{id} 链接）
    this.tools.web_register_webhook = {
      name: 'web_register_webhook',
      description: '注册 Webhook，接收的数据会交给 LLM 处理。自动生成唯一 URL',
      inputSchema: z.object({
        prompt: z.string().optional().describe('提示词，描述如何处理请求'),
        awaitResponse: z.boolean().optional().describe('是否等待 LLM 处理完成再返回响应，默认 false')
      }),
      execute: async (args) => this._registerWebhook(args.prompt, args.awaitResponse)
    }

    // 注册静态资源
    this.tools.web_register_static = {
      name: 'web_register_static',
      description: '注册静态资源文件夹',
      inputSchema: z.object({
        urlPath: z.string().describe('URL 路径前缀，如 /public'),
        folder: z.string().describe('本地文件夹路径，如 ./static'),
        options: z.object({
          dotfiles: z.enum(['ignore', 'allow', 'deny']).optional(),
          index: z.string().optional()
        }).optional()
      }),
      execute: async (args) => this._registerStatic(args.urlPath, args.folder, args.options)
    }

    // 列出所有路由
    this.tools.web_list_routes = {
      name: 'web_list_routes',
      description: '列出所有已注册的路由和 Webhook',
      inputSchema: z.object({}),
      execute: async () => this._listRoutes()
    }

    // 删除路由
    this.tools.web_delete_route = {
      name: 'web_delete_route',
      description: '删除已注册的 HTTP 路由',
      inputSchema: z.object({
        method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).describe('HTTP 方法'),
        path: z.string().describe('路由路径，如 /api/user')
      }),
      execute: async (args) => this._deleteRoute(args.method, args.path)
    }

    // 删除 Webhook
    this.tools.web_delete_webhook = {
      name: 'web_delete_webhook',
      description: '删除已注册的 Webhook',
      inputSchema: z.object({
        id: z.string().describe('Webhook ID')
      }),
      execute: async (args) => this._deleteWebhook(args.id)
    }

    // 删除静态资源
    this.tools.web_delete_static = {
      name: 'web_delete_static',
      description: '删除已注册的静态资源文件夹',
      inputSchema: z.object({
        urlPath: z.string().describe('URL 路径前缀，如 /public')
      }),
      execute: async (args) => this._deleteStatic(args.urlPath)
    }

    // 发送 HTTP 请求
    this.tools.web_request = {
      name: 'web_request',
      description: '发送 HTTP 请求',
      inputSchema: z.object({
        method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).describe('HTTP 方法'),
        path: z.string().describe('请求路径'),
        body: z.any().optional().describe('请求体'),
        headers: z.record(z.string()).optional().describe('请求头')
      }),
      execute: async (args) => this._sendRequest(args.method, args.path, args.body, args.headers)
    }
  }

  // ==================== 服务器控制 ====================

  async _startServer(port, host) {
    if (this._server) {
      return { success: true, message: 'Server already running', port: this._port }
    }

    this._port = port || this._port
    this._host = host || this._host

    this._app = new Hono()
    this._setupMiddleware()

    try {
      this._server = serve({
        fetch: this._app.fetch,
        port: this._port,
        hostname: this._host
      })
      const serverUrl = this._getUrl()
      log.info(` Server started on ${serverUrl}`)
      return {
        success: true,
        message: `Server started on ${serverUrl}`,
        // port: this._port,
        // host: this._host,
        host: serverUrl,
        url:serverUrl,
      }
    } catch (err) {
      this._server = null
      this._app = null
      if (err.code === 'EADDRINUSE') {
        return { success: false, error: `Port ${this._port} is already in use` }
      }
      return { success: false, error: err.message }
    }
  }

  async _stopServer() {
    if (!this._server) {
      return { success: true, message: 'Server not running' }
    }
    this._server.close()
    this._server = null
    this._app = null
    log.info(' Server stopped')
    return { success: true, message: 'Server stopped' }
  }

  // ==================== 中间件 ====================

  _setupMiddleware() {
    this._app.use('*', async (c) => {
      const pathname = c.req.path

      // CORS 预检
      if (c.req.method === 'OPTIONS') {
        return c.text('', 200, {
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type, Authorization'
        })
      }

      // 1. 静态文件
      const staticResult = this._serveStatic(pathname)
      if (staticResult) {
        if (staticResult.type === 'file') {
          return c.newResponse(staticResult.content, {
            headers: { 'Content-Type': staticResult.contentType }
          })
        }
        if (staticResult.type === 'notFound') {
          return c.json({ error: 'Not Found' }, 404)
        }
        if (staticResult.type === 'forbidden') {
          return c.json({ error: 'Forbidden' }, 403)
        }
        if (staticResult.type === 'error') {
          return c.json({ error: staticResult.message }, 500)
        }
      }

      // 2. Webhook（仅接受 POST）
      const webhook = this._webhooks.get(pathname)
      if (webhook) {
        if (c.req.method !== 'POST') {
          return c.json({ success: false, error: 'Method Not Allowed. Webhook only accepts POST.' }, 405)
        }
        const result = await this._handleWebhook(c, webhook)
        return c.json(result)
      }

      // 3. 路由（支持参数）
      for (const route of this._routes) {
        if (route.method === c.req.method && this._matchPath(route.path, pathname)) {
          return await this._handleRoute(c, route, pathname)
        }
      }

      // 404
      return c.json({ success: false, error: 'Not Found', path: pathname }, 404)
    })
  }

  // ==================== 请求处理 ====================

  async _handleRoute(c, route, pathname) {
    const params = this._extractParams(route.path, pathname)
    const query = this._parseQuery(c)
    const body = await this._parseBody(c)

    const context = { params, query, body }

    // 构建 tools 代理对象，允许 handler 以函数方式直接调用工具
    // 例如: const user = await tools.get_user({ id: 1 })
    const registry = this._framework.toolRegistry
    const tools = new Proxy({}, {
      get: (_, name) => {
        if (name === 'call') {
          // 保留 call 方式作为后备
          return async (toolName, args) => registry.execute(toolName, args || {}, this._framework)
        }
        return async (args) => registry.execute(name, args || {}, this._framework)
      }
    })

    const result = await this._executeHandler(route.handler, context, tools)
    return c.json(result)
  }

  async _handleWebhook(c, webhook) {
    const query = this._parseQuery(c)
    const body = await this._parseBody(c)
    const webhookData = {
      path: webhook.path,
      method: c.req.method,
      query,
      body,
      timestamp: new Date().toISOString()
    }

    // 从执行上下文获取 sessionId
    const ctx = this._framework.getExecutionContext()
    const sessionId = ctx?.sessionId || null

    // 获取 Agent
    const agent = this._getAgent(sessionId)
    if (!agent) {
      log.error(' No agent available')
      return { success: false, error: 'No agent available' }
    }

    const prompt = webhook.prompt || '处理以下 webhook 数据，返回适当的响应：'
    const finalSessionId = sessionId || `web_${Date.now()}`

    // 触发 webhook 接收事件（扁平化结构）
    this._framework.emit('webhook:received', {
      path: webhook.path,
      method: c.req.method,
      query,
      body,
      timestamp: webhookData.timestamp
    })

    // 使用子Agent处理 webhook
    const webhookAgent = this._framework.createSubAgent({
      name: 'webhook_handler',
      role: 'Webhook处理助手，专注于处理webhook数据并生成适当响应'
    })

    if (!webhook.awaitResponse) {
      // 不等待，立即返回
      webhookAgent.chat(`${prompt}\n\n数据:\n${JSON.stringify(webhookData, null, 2)}`).then(result => {
        const responseText = result.message || result.text || ''
        log.info(` Webhook processed (${webhook.path}), LLM response (${responseText.length} chars)`)

        // 添加到 session 历史
        if (sessionId) {
          const sessionPlugin = this._framework.pluginManager.get('session')
          if (sessionPlugin) {
            sessionPlugin.addMessage(sessionId, { role: 'user', content: `【Webhook 数据】\n${JSON.stringify(webhookData, null, 2)}` })
            sessionPlugin.addMessage(sessionId, { role: 'assistant', content: responseText })
          }
        }

        // 触发 webhook 处理完成事件
        this._framework.emit('webhook:processed', {
          path: webhook.path,
          method: c.req.method,
          query,
          body,
          response: responseText,
          timestamp: webhookData.timestamp
        })
      }).catch(err => {
        log.error(' Webhook error:', err.message)
      })

      return { success: true, message: 'Webhook received, processing in background' }
    }

    // 等待 LLM 处理完成
    try {
      const result = await webhookAgent.chat(`${prompt}\n\n数据:\n${JSON.stringify(webhookData, null, 2)}`)
      const responseText = result.message || result.text || ''
      log.info(` Webhook processed (${webhook.path}), LLM response (${responseText.length} chars)`)

      // 添加到 session 历史
      if (sessionId) {
        const sessionPlugin = this._framework.pluginManager.get('session')
        if (sessionPlugin) {
          sessionPlugin.addMessage(sessionId, { role: 'user', content: `【Webhook 数据】\n${JSON.stringify(webhookData, null, 2)}` })
          sessionPlugin.addMessage(sessionId, { role: 'assistant', content: responseText })
        }
      }

      // 触发 webhook 处理完成事件
      this._framework.emit('webhook:processed', {
        path: webhook.path,
        method: c.req.method,
        query,
        body,
        response: responseText,
        timestamp: webhookData.timestamp
      })

      return { success: true, message: 'Webhook processed', response: responseText }
    } catch (err) {
      log.error(' Webhook error:', err.message)
      return { success: false, error: err.message }
    }
  }

  // ==================== 路由注册 ====================

  async _registerRoute(method, path, handler, description) {
    if (!path.startsWith('/') || path.length < 2) {
      return { success: false, error: 'Invalid path format' }
    }

    if (!this._server) {
      await this._startServer()
    }

    const route = { method: method.toUpperCase(), path, handler, description: description || '' }
    const index = this._routes.findIndex(r => r.method === route.method && r.path === path)
    if (index >= 0) {
      this._routes[index] = route
    } else {
      this._routes.push(route)
    }

    // 持久化保存
    this._saveConfig()

    log.info(` Route registered: ${method} ${path}`)
    return { success: true, message: `Route ${method} ${path} registered`, url: this._getUrl(path), route: { method, path, description } }
  }

  async _registerWebhook(prompt, awaitResponse = false) {
    if (!this._server) {
      await this._startServer()
    }

    // 生成唯一 ID 和路径：/webhook/{id}
    const id = this._generateId()
    const webhookPath = `/webhook/${id}`

    this._webhooks.set(webhookPath, {
      id,
      path: webhookPath,
      prompt: prompt || '处理以下 webhook 数据，返回适当的响应：',
      awaitResponse
    })

    // 持久化保存
    this._saveConfig()

    log.info(` Webhook registered: ${webhookPath}`)
    return {
      success: true,
      message: `Webhook registered`,
      webhook: {
        id,
        path: webhookPath,
        url: this._getUrl(webhookPath)
      }
    }
  }

  async _registerStatic(urlPath, folder, options = {}) {
    if (!this._server) {
      await this._startServer()
    }

    const normalizedPath = urlPath.endsWith('/') ? urlPath : urlPath + '/'
    this._statics.push({
      urlPath: normalizedPath,
      folder: path.resolve(folder),
      options: {
        dotfiles: options.dotfiles || 'ignore',
        index: options.index || 'index.html'
      }
    })

    // 持久化保存
    this._saveConfig()

    log.info(` Static registered: ${normalizedPath} -> ${folder}`)
    return {
      success: true,
      message: `Static folder registered`,
      url: this._getUrl(normalizedPath)
    }
  }

  _listRoutes() {
    const baseUrl = this._getUrl()

    return {
      success: true,
      server: this._server ? { running: true, host: this._host, port: this._port } : { running: false },
      routes: this._routes.map(r => ({ type: 'route', method: r.method, path: r.path, description: r.description })),
      webhooks: Array.from(this._webhooks.values()).map(w => ({ type: 'webhook', id: w.id, path: w.path, url: `${baseUrl}${w.path}`, prompt: w.prompt })),
      statics: this._statics.map(s => ({ type: 'static', path: s.urlPath, folder: s.folder, url: `${baseUrl}${s.urlPath}` }))
    }
  }

  async _deleteRoute(method, path) {
    const index = this._routes.findIndex(r => r.method === method.toUpperCase() && r.path === path)
    if (index < 0) {
      return { success: false, error: `Route not found: ${method} ${path}` }
    }

    this._routes.splice(index, 1)
    this._saveConfig()
    log.info(` Route deleted: ${method} ${path}`)
    return { success: true, message: `Route deleted: ${method} ${path}` }
  }

  async _deleteWebhook(id) {
    let found = null
    for (const [path, webhook] of this._webhooks.entries()) {
      if (webhook.id === id) {
        found = path
        break
      }
    }

    if (!found) {
      return { success: false, error: `Webhook not found: ${id}` }
    }

    this._webhooks.delete(found)
    this._saveConfig()
    log.info(` Webhook deleted: ${found}`)
    return { success: true, message: `Webhook deleted: ${found}` }
  }

  async _deleteStatic(urlPath) {
    const normalizedPath = urlPath.endsWith('/') ? urlPath : urlPath + '/'
    const index = this._statics.findIndex(s => s.urlPath === normalizedPath)
    if (index < 0) {
      return { success: false, error: `Static folder not found: ${urlPath}` }
    }

    this._statics.splice(index, 1)
    this._saveConfig()
    log.info(` Static deleted: ${normalizedPath}`)
    return { success: true, message: `Static folder deleted: ${normalizedPath}` }
  }

  // ==================== HTTP 客户端 ====================

  async _sendRequest(method, urlPath, body, headers) {
    if (!this._server) {
      return { success: false, error: 'Server not started' }
    }

    const url = this._getUrl(urlPath)
    try {
      const options = {
        method: method.toUpperCase(),
        headers: headers || {}
      }

      if (body && !['GET', 'HEAD'].includes(options.method)) {
        options.body = JSON.stringify(body)
        options.headers['Content-Type'] = options.headers['Content-Type'] || 'application/json'
      }

      const response = await fetch(url, options)
      const text = await response.text()
      let parsed = text
      try { parsed = JSON.parse(text) } catch { /* not JSON */ }

      return { success: true, status: response.status, headers: Object.fromEntries(response.headers.entries()), body: parsed }
    } catch (err) {
      return { success: false, error: err.message }
    }
  }

  // ==================== 工具方法 ====================

  _matchPath(routePath, reqPath) {
    const routeParts = routePath.split('/').filter(Boolean)
    const reqParts = reqPath.split('/').filter(Boolean)
    if (routeParts.length !== reqParts.length) return false
    return routeParts.every((part, i) => part.startsWith(':') || part === reqParts[i])
  }

  _extractParams(routePath, reqPath) {
    const params = {}
    const routeParts = routePath.split('/').filter(Boolean)
    const reqParts = reqPath.split('/').filter(Boolean)
    routeParts.forEach((part, i) => {
      if (part.startsWith(':')) {
        params[part.substring(1)] = reqParts[i]
      }
    })
    return params
  }

  _parseQuery(c) {
    const raw = c.req.queries() || {}
    const query = {}
    for (const [key, value] of Object.entries(raw)) {
      query[key] = value.length === 1 ? value[0] : value
    }
    return query
  }

  async _parseBody(c) {
    try {
      const rawText = await c.req.text()
      log.info(rawText)
      if (!rawText) return {}
      return JSON.parse(rawText)
    } catch (e) {
      return {}
    }
  }

  _getUrl(path='') {
    if (this._baseUrl) {
      return `${this._baseUrl}${path}`
    }
    return `http://${this._host}:${this._port}${path}`
  }

  async _executeHandler(handlerCode, context, tools) {
    try {
      // 辅助函数
      const helpers = {
        // 基础工具
        echo: (val) => val,
        json: (val) => JSON.stringify(val),
        JSON: JSON,
        // 日期时间
        Date: Date,
        now: () => Date.now(),
        // 字符串
        Str: String,
        // 编码
        btoa: (str) => Buffer.from(str).toString('base64'),
        atob: (str) => Buffer.from(str, 'base64').toString(),
        // 格式化
        template: (str, vars) => str.replace(/\{\{(\w+)\}\}/g, (_, k) => vars[k] ?? `{{${k}}}`),
        // 随机
        uuid: () => Math.random().toString(36).substring(2) + Date.now().toString(36),
        // HTTP 请求（通过 fetch）
        fetch: async (url, options = {}) => {
          const { method = 'GET', headers = {}, body } = options
          const res = await fetch(url, { method, headers, body })
          return { status: res.status, headers: Object.fromEntries(res.headers), body: await res.text() }
        }
      }
      // 使用沙箱执行用户代码，防止恶意代码执行
      return await runInSandbox(handlerCode, { context, tools, ...helpers }, { timeout: 10000 })
    } catch (err) {
      return { success: false, error: `Handler error: ${err.message}` }
    }
  }

  _serveStatic(pathname) {
    for (const staticFolder of this._statics) {
      if (pathname.startsWith(staticFolder.urlPath)) {
        const relativePath = pathname.substring(staticFolder.urlPath.length) || staticFolder.options.index
        const filePath = path.join(staticFolder.folder, relativePath)

        // 安全检查
        if (!filePath.startsWith(staticFolder.folder)) {
          return { type: 'forbidden' }
        }
        if (staticFolder.options.dotfiles === 'deny' && path.basename(filePath).startsWith('.')) {
          return { type: 'notFound' }
        }

        try {
          const content = fs.readFileSync(filePath)
          const ext = path.extname(filePath).toLowerCase()
          const contentTypes = {
            '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript',
            '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg',
            '.gif': 'image/gif', '.svg': 'image/svg+xml', '.ico': 'image/x-icon',
            '.txt': 'text/plain'
          }
          const contentType = contentTypes[ext] || 'application/octet-stream'
          return { type: 'file', content, contentType }
        } catch (err) {
          if (err.code === 'ENOENT') {
            return { type: 'notFound' }
          }
          return { type: 'error', message: err.message }
        }
      }
    }
    return null
  }

  _generateId() {
    return Math.random().toString(36).substring(2, 10) + Date.now().toString(36)
  }

  _getAgent(sessionId) {
    const finalSessionId = sessionId || `web_${Date.now()}`

    // 尝试从对应平台插件获取 Agent
    const platformPrefixes = ['weixin_', 'telegram_', 'feishu_']
    for (const prefix of platformPrefixes) {
      if (finalSessionId.startsWith(prefix)) {
        const pluginName = prefix.replace('_', '')
        const plugin = this._framework.pluginManager.get(pluginName)
        if (plugin?._sessionAgents?.size > 0) {
          const firstAgent = plugin._sessionAgents.values().next().value
          if (firstAgent) return firstAgent
        }
      }
    }

    // 返回主 Agent
    return this._framework._mainAgent || this._framework._agents?.[0]
  }
}

module.exports = WebPlugin
