/**
 * Memory 记忆插件
 * 四层记忆系统：user, feedback, project, reference
 */

const { Plugin } = require('../src/core/plugin-base')
const { logger } = require('../src/utils/logger')
const log = logger.child('Memory')
const { z } = require('zod')
const fs = require('fs')
const path = require('path')
const { EventEmitter } = require('events')
const {cleanResponse} =require('../src/utils')
/**
 * 记忆类型常量
 */
const MEMORY_TYPES = {
  USER: 'user',
  FEEDBACK: 'feedback',
  PROJECT: 'project',
  REFERENCE: 'reference'
}

/**
 * 记忆存储路径
 */
const MEMORY_BASE_DIR = '.agent/memory'

/**
 * 解析 YAML frontmatter（从 skill-manager 复用）
 */
function parseFrontmatter(content) {
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
  if (!match) return null

  const frontmatter = {}
  const lines = match[1].split('\n')
  let currentKey = null

  for (const line of lines) {
    if (currentKey === 'metadata') {
      if (line.match(/^ {2}[a-zA-Z]/)) {
        const colonIndex = line.indexOf(':')
        if (colonIndex > 0) {
          const key = line.substring(2, colonIndex).trim()
          const value = line.substring(colonIndex + 1).trim().replace(/^["']|["']$/g, '')
          frontmatter[currentKey][key] = value
          continue
        }
      } else if (line.match(/^[a-zA-Z]/)) {
        currentKey = null
        continue
      }
    }

    const colonIndex = line.indexOf(':')
    if (colonIndex === -1) continue

    const key = line.substring(0, colonIndex).trim()
    let value = line.substring(colonIndex + 1).trim()

    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1)
    }

    if (key === 'metadata') {
      currentKey = 'metadata'
      frontmatter.metadata = {}
    } else if (key === 'tags') {
      frontmatter[key] = value
        .split(',')
        .map(t => t.trim().replace(/^["']|["']$/g, ''))
        .filter(t => t)
    } else {
      frontmatter[key] = value
    }
  }

  return frontmatter
}

/**
 * 序列化 frontmatter
 */
function serializeFrontmatter(data) {
  const lines = ['---']
  for (const [key, value] of Object.entries(data)) {
    if (key === 'metadata') {
      lines.push('metadata:')
      for (const [mk, mv] of Object.entries(value)) {
        lines.push(`  ${mk}: "${mv}"`)
      }
    } else if (Array.isArray(value)) {
      lines.push(`${key}: [${value.join(', ')}]`)
    } else {
      lines.push(`${key}: "${value}"`)
    }
  }
  lines.push('---')
  return lines.join('\n')
}

/**
 * 路径安全检查
 */
function sanitizeMemoryPath(relativePath, baseDir) {
  // 拒绝绝对路径
  if (path.isAbsolute(relativePath)) {
    throw new Error('Absolute paths are not allowed')
  }

  // 拒绝包含 .. 的路径
  if (relativePath.includes('..')) {
    throw new Error('Parent directory references are not allowed')
  }

  // 解析并验证最终路径在 baseDir 内
  const resolved = path.resolve(baseDir, relativePath)
  const baseResolved = path.resolve(baseDir)

  if (!resolved.startsWith(baseResolved)) {
    throw new Error('Path outside memory directory is not allowed')
  }

  return resolved
}

/**
 * 生成记忆 ID
 */
function generateMemoryId() {
  const timestamp = Date.now().toString(36)
  const random = Math.random().toString(36).substring(2, 8)
  return `${timestamp}-${random}`
}

/**
 * 从文本中提取 JSON 对象（处理嵌套括号）
 * @param {string} text - 输入文本
 * @returns {string|null} 提取的 JSON 字符串，失败返回 null
 */
function _extractJSON(text) {
  if (!text || typeof text !== 'string') return null

  // 去掉首尾空白
  text = text.trim()

  // 方法1：如果直接以 { 开头，尝试直接解析
  if (text.startsWith('{')) {
    // 查找配对的括号位置
    let braceCount = 0
    let inString = false
    let escaped = false

    for (let i = 0; i < text.length; i++) {
      const char = text[i]

      if (escaped) {
        escaped = false
        continue
      }

      if (char === '\\' && inString) {
        escaped = true
        continue
      }

      if (char === '"') {
        inString = !inString
        continue
      }

      if (!inString) {
        if (char === '{') {
          braceCount++
        } else if (char === '}') {
          braceCount--
          if (braceCount === 0) {
            return text.substring(0, i + 1)
          }
        }
      }
    }
  }

  // 方法2：从 thinking 文本中查找 JSON（处理 AI 输出 thinking 的情况）
  // 查找最后一个 { 到最后一个 } 之间的内容
  const firstBrace = text.indexOf('{')
  const lastBrace = text.lastIndexOf('}')

  if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
    const potential = text.substring(firstBrace, lastBrace + 1)
    try {
      JSON.parse(potential) // 验证是否是有效 JSON
      return potential
    } catch (e) {
      // 不是有效 JSON，继续尝试其他方法
    }
  }

  return null
}

/**
 * MemoryStore - 双层存储（内存 + 文件）
 */
class MemoryStore extends EventEmitter {
  constructor(baseDir) {
    super()
    this._baseDir = path.resolve(process.cwd(), baseDir)
    this._memory = new Map() // memoryId -> memory object
    this._indexByType = new Map() // type -> Set of memoryIds
    this._indexByProject = new Map() // project -> Set of memoryIds
    this._fileIndex = new Map() // memoryId -> filePath

    // 初始化目录结构
    this._initDirs()
    // 加载已有记忆
    this._loadAll()
  }

  _initDirs() {
    const dirs = [
      this._baseDir,
      path.join(this._baseDir, 'user'),
      path.join(this._baseDir, 'feedback'),
      path.join(this._baseDir, 'project'),
      path.join(this._baseDir, 'reference')
    ]

    for (const dir of dirs) {
      if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true })
      }
    }
  }

  _getTypeDir(type) {
    return path.join(this._baseDir, type)
  }

  _loadAll() {
    for (const type of Object.values(MEMORY_TYPES)) {
      const typeDir = this._getTypeDir(type)
      if (!fs.existsSync(typeDir)) continue

      try {
        const files = fs.readdirSync(typeDir)
        for (const file of files) {
          if (!file.endsWith('.md')) continue
          const filePath = path.join(typeDir, file)
          try {
            const memory = this._loadFromFile(filePath)
            if (memory && memory.id) {
              this._addToIndexes(memory)
              this._fileIndex.set(memory.id, filePath)
            }
          } catch (err) {
            log.warn(`Failed to load memory from ${filePath}:`, err.message)
          }
        }
      } catch (err) {
        log.warn(`Failed to read memory directory ${typeDir}:`, err.message)
      }
    }

    log.info(`Loaded ${this._memory.size} memories from disk`)
  }

  _loadFromFile(filePath) {
    const content = fs.readFileSync(filePath, 'utf-8')
    const frontmatter = parseFrontmatter(content)

    if (!frontmatter) {
      return null
    }

    // 移除 frontmatter 获取正文
    const contentMatch = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?([\s\S]*)$/)
    const body = contentMatch ? contentMatch[1].trim() : content

    return {
      id: frontmatter.id || path.basename(filePath, '.md'),
      name: frontmatter.name || '',
      type: frontmatter.type || 'user',
      project: frontmatter.project || null,
      tags: frontmatter.tags || [],
      created: frontmatter.created || new Date().toISOString().split('T')[0],
      body
    }
  }

  _saveToFile(memory) {
    const typeDir = this._getTypeDir(memory.type)
    const fileName = `${memory.id}.md`
    const filePath = path.join(typeDir, fileName)

    const frontmatter = {
      id: memory.id,
      name: memory.name,
      type: memory.type,
      project: memory.project,
      tags: memory.tags,
      created: memory.created
    }

    const content = serializeFrontmatter(frontmatter) + '\n' + memory.body
    fs.writeFileSync(filePath, content, 'utf-8')
    return filePath
  }

  _addToIndexes(memory) {
    this._memory.set(memory.id, memory)

    // 按类型索引
    if (!this._indexByType.has(memory.type)) {
      this._indexByType.set(memory.type, new Set())
    }
    this._indexByType.get(memory.type).add(memory.id)

    // 按项目索引
    if (memory.project) {
      if (!this._indexByProject.has(memory.project)) {
        this._indexByProject.set(memory.project, new Set())
      }
      this._indexByProject.get(memory.project).add(memory.id)
    }
  }

  _removeFromIndexes(memory) {
    this._memory.delete(memory.id)

    const typeSet = this._indexByType.get(memory.type)
    if (typeSet) typeSet.delete(memory.id)

    if (memory.project) {
      const projectSet = this._indexByProject.get(memory.project)
      if (projectSet) projectSet.delete(memory.id)
    }
  }

  // 公开 API

  /**
   * 添加记忆
   */
  add(memory) {
    const id = memory.id || generateMemoryId()
    const now = new Date().toISOString().split('T')[0]

    const newMemory = {
      id,
      name: memory.name || '',
      type: memory.type || MEMORY_TYPES.USER,
      project: memory.project || null,
      tags: memory.tags || [],
      created: memory.created || now,
      body: memory.body || ''
    }

    // 验证类型
    if (!Object.values(MEMORY_TYPES).includes(newMemory.type)) {
      throw new Error(`Invalid memory type: ${newMemory.type}`)
    }

    const filePath = this._saveToFile(newMemory)
    this._addToIndexes(newMemory)
    this._fileIndex.set(id, filePath)

    log.debug(`Added memory: ${id} (${newMemory.type})`)

    // 触发变化事件
    this.emit('change', { action: 'add', memory: newMemory })

    return newMemory
  }

  /**
   * 获取记忆
   */
  get(id) {
    return this._memory.get(id) || null
  }

  /**
   * 更新记忆
   */
  update(id, updates) {
    const memory = this._memory.get(id)
    if (!memory) {
      throw new Error(`Memory not found: ${id}`)
    }

    const oldType = memory.type
    const oldProject = memory.project

    // 应用更新
    if (updates.name !== undefined) memory.name = updates.name
    if (updates.type !== undefined) memory.type = updates.type
    if (updates.project !== undefined) memory.project = updates.project
    if (updates.tags !== undefined) memory.tags = updates.tags
    if (updates.body !== undefined) memory.body = updates.body

    // 如果类型或项目改变，需要重建索引
    if (oldType !== memory.type || oldProject !== memory.project) {
      this._removeFromIndexes({ ...memory, type: oldType, project: oldProject })
      this._addToIndexes(memory)
    }

    // 重新保存文件
    const filePath = this._saveToFile(memory)
    this._fileIndex.set(id, filePath)

    log.debug(`Updated memory: ${id}`)

    // 触发变化事件
    this.emit('change', { action: 'update', memory })

    return memory
  }

  /**
   * 删除记忆
   */
  delete(id) {
    const memory = this._memory.get(id)
    if (!memory) {
      return false
    }

    // 删除文件
    const filePath = this._fileIndex.get(id)
    if (filePath && fs.existsSync(filePath)) {
      fs.unlinkSync(filePath)
    }

    this._removeFromIndexes(memory)
    this._fileIndex.delete(id)

    log.debug(`Deleted memory: ${id}`)

    // 触发变化事件
    this.emit('change', { action: 'delete', memory })

    return true
  }

  /**
   * 搜索记忆
   */
  search(query, options = {}) {
    const { type, project, tags, limit = 50 } = options
    let results = []

    // 根据类型筛选
    if (type) {
      const typeSet = this._indexByType.get(type)
      if (typeSet) {
        results = Array.from(typeSet).map(id => this._memory.get(id)).filter(Boolean)
      }
    } else {
      results = Array.from(this._memory.values())
    }

    // 根据项目筛选
    if (project) {
      results = results.filter(m => m.project === project)
    }

    // 根据标签筛选
    if (tags && tags.length > 0) {
      results = results.filter(m =>
        tags.some(tag => m.tags && m.tags.includes(tag))
      )
    }

    // 根据查询字符串搜索（名称 + 正文）
    if (query && query.trim()) {
      const lowerQuery = query.toLowerCase()
      results = results.filter(m =>
        m.name.toLowerCase().includes(lowerQuery) ||
        m.body.toLowerCase().includes(lowerQuery)
      )
    }

    // 限制返回数量
    return results.slice(0, limit)
  }

  /**
   * 列出指定类型的所有记忆
   */
  listByType(type, limit = 100) {
    const typeSet = this._indexByType.get(type)
    if (!typeSet) return []
    return Array.from(typeSet)
      .map(id => this._memory.get(id))
      .filter(Boolean)
      .slice(0, limit)
  }

  /**
   * 按项目列出记忆
   */
  listByProject(project, limit = 100) {
    const projectSet = this._indexByProject.get(project)
    if (!projectSet) return []
    return Array.from(projectSet)
      .map(id => this._memory.get(id))
      .filter(Boolean)
      .slice(0, limit)
  }

  /**
   * 获取所有项目列表
   */
  getProjects() {
    return Array.from(this._indexByProject.keys())
  }

  /**
   * 获取统计信息
   */
  getStats() {
    const stats = {}
    for (const type of Object.values(MEMORY_TYPES)) {
      const typeSet = this._indexByType.get(type)
      stats[type] = typeSet ? typeSet.size : 0
    }
    stats.total = this._memory.size
    return stats
  }
}

/**
 * MemoryPlugin
 */
class MemoryPlugin extends Plugin {
  constructor(config = {}) {
    super()
    this.name = 'memory'
    this.version = '1.0.0'
    this.description = '四层记忆系统，支持 user/feedback/project/reference 四种记忆类型'
    this.priority = 6 // 在 session 之后加载

    this.system = true

    this.config = {
      memoryDir: config.memoryDir || MEMORY_BASE_DIR,
      autoExtract: config.autoExtract !== false, // 默认开启自动提取
      extractOnTopics: ['provider', 'preference', 'setting', 'user'] // 触发自动提取的关键词
    }

    this._framework = null
    this._store = null
    this._memoryAgent = null // 用于记忆提取的子 agent
    this._isExtracting = false // 防止递归调用的标志
  }

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

  start(framework) {
    // 初始化存储
    this._store = new MemoryStore(this.config.memoryDir)

    // 创建复用的记忆提取子 Agent
    this._memoryAgent = framework.createSubAgent({
      name: 'memory-extractor',
      role: '记忆提取专家',
      description: '专门负责从对话和错误中提取记忆的子 Agent',
      tools: {}, // 不需要额外工具，隔离主 Agent 工具
      parentTools: [] // 不继承任何工具，纯粹做提取
    })

    // 注册工具
    this._registerTools(framework)

    // 设置自动记忆提取（监听对话结束事件）
    if (this.config.autoExtract) {
      this._setupAutoExtract(framework)
    }

    // 注册 memory-context 到系统提示（优先级 350）
    this._registerMemoryContext(framework)

    // 监听记忆变化，动态刷新系统提示词
    this._setupDynamicRefresh(framework)

    log.info('Memory plugin started')
    return this
  }

  _registerTools(framework) {
    // memory_search - 搜索记忆
    framework.registerTool({
      name: 'memory_search',
      description: '搜索记忆库，支持按类型、项目、标签搜索',
      inputSchema: z.object({
        query: z.string().optional().describe('搜索关键词'),
        type: z.enum(['user', 'feedback', 'project', 'reference']).optional().describe('记忆类型'),
        project: z.string().optional().describe('项目名称'),
        tags: z.array(z.string()).optional().describe('标签列表'),
        limit: z.number().optional().describe('返回数量限制，默认 50')
      }),
      execute: async (args) => {
        try {
          const results = this._store.search(args.query, {
            type: args.type,
            project: args.project,
            tags: args.tags,
            limit: args.limit || 50
          })

          return {
            success: true,
            count: results.length,
            memories: results.map(m => ({
              id: m.id,
              name: m.name,
              type: m.type,
              project: m.project,
              tags: m.tags,
              created: m.created,
              preview: m.body.substring(0, 200)
            }))
          }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })

    // memory_write - 写入记忆
    framework.registerTool({
      name: 'memory_write',
      description: '写入新的记忆，支持 YAML frontmatter',
      inputSchema: z.object({
        name: z.string().describe('记忆名称'),
        type: z.enum(['user', 'feedback', 'project', 'reference']).describe('记忆类型'),
        project: z.string().optional().describe('关联项目'),
        tags: z.array(z.string()).optional().describe('标签'),
        content: z.string().describe('记忆内容')
      }),
      execute: async (args) => {
        try {
          const memory = this._store.add({
            name: args.name,
            type: args.type,
            project: args.project || null,
            tags: args.tags || [],
            body: args.content
          })

          return {
            success: true,
            id: memory.id,
            message: `Memory created: ${memory.id}`
          }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })

    // memory_list - 列出记忆
    framework.registerTool({
      name: 'memory_list',
      description: '列出指定类型的记忆',
      inputSchema: z.object({
        type: z.enum(['user', 'feedback', 'project', 'reference']).describe('记忆类型'),
        project: z.string().optional().describe('项目名称（当类型为 project 时）'),
        limit: z.number().optional().describe('返回数量限制，默认 100')
      }),
      execute: async (args) => {
        try {
          let memories
          if (args.type === 'project' && args.project) {
            memories = this._store.listByProject(args.project, args.limit || 100)
          } else {
            memories = this._store.listByType(args.type, args.limit || 100)
          }

          return {
            success: true,
            count: memories.length,
            memories: memories.map(m => ({
              id: m.id,
              name: m.name,
              type: m.type,
              project: m.project,
              tags: m.tags,
              created: m.created,
              preview: m.body.substring(0, 200)
            }))
          }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })

    // memory_delete - 删除记忆
    framework.registerTool({
      name: 'memory_delete',
      description: '删除指定记忆',
      inputSchema: z.object({
        id: z.string().describe('记忆 ID')
      }),
      execute: async (args) => {
        try {
          const deleted = this._store.delete(args.id)
          return { success: deleted, deleted: args.id }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })

    // memory_update - 更新记忆
    framework.registerTool({
      name: 'memory_update',
      description: '更新已有记忆',
      inputSchema: z.object({
        id: z.string().describe('记忆 ID'),
        name: z.string().optional().describe('新名称'),
        type: z.enum(['user', 'feedback', 'project', 'reference']).optional().describe('新类型'),
        project: z.string().optional().describe('新关联项目'),
        tags: z.array(z.string()).optional().describe('新标签'),
        content: z.string().optional().describe('新内容')
      }),
      execute: async (args) => {
        try {
          const updates = {}
          if (args.name !== undefined) updates.name = args.name
          if (args.type !== undefined) updates.type = args.type
          if (args.project !== undefined) updates.project = args.project
          if (args.tags !== undefined) updates.tags = args.tags
          if (args.content !== undefined) updates.body = args.content

          const memory = this._store.update(args.id, updates)
          return {
            success: true,
            id: memory.id,
            message: `Memory updated: ${memory.id}`
          }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })

    // memory_get - 获取单条记忆详情
    framework.registerTool({
      name: 'memory_get',
      description: '获取单条记忆的完整内容',
      inputSchema: z.object({
        id: z.string().describe('记忆 ID')
      }),
      execute: async (args) => {
        try {
          const memory = this._store.get(args.id)
          if (!memory) {
            return { success: false, error: 'Memory not found' }
          }
          return {
            success: true,
            memory: {
              id: memory.id,
              name: memory.name,
              type: memory.type,
              project: memory.project,
              tags: memory.tags,
              created: memory.created,
              content: memory.body
            }
          }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })

    // memory_stats - 获取记忆统计
    framework.registerTool({
      name: 'memory_stats',
      description: '获取记忆统计信息',
      inputSchema: z.object({}),
      execute: async () => {
        try {
          const stats = this._store.getStats()
          const projects = this._store.getProjects()
          return {
            success: true,
            stats,
            projects
          }
        } catch (err) {
          return { success: false, error: err.message }
        }
      }
    })
  }

  /**
   * 设置自动记忆提取
   */
  _setupAutoExtract(framework) {
    // 监听 agent 消息完成事件，在对话轮次结束时提取记忆
    framework.on('agent:message', async ({ userMessage, assistantResponse }) => {
      // 防止递归调用：如果正在提取中，跳过此次事件
      if (this._isExtracting) {
        log.debug('Skipping agent:message event during memory extraction')
        return
      }

      try {
        await this._extractMemoryFromConversation(userMessage, assistantResponse)
      } catch (err) {
        log.warn('Auto memory extraction failed:', err.message)
      }
    })

    // 监听所有工具调用错误（包括 ext_call, MCP, 原生工具等）
    framework.on('tool:error', async (data) => {
      try {
        await this._extractErrorLesson({
          name: data.name || data.tool || 'unknown-tool',
          args: data.args || {},
          error: data.error || data.message || String(data),
          source: data.source || 'tool'
        })
      } catch (err) {
        log.warn('Auto tool error lesson extraction failed:', err.message)
      }
    })

    // 监听 tool-call 别名（AI SDK 6.x 格式）
    framework.on('tool-error', async (data) => {
      try {
        await this._extractErrorLesson({
          name: data.name || data.tool || 'unknown-tool',
          args: data.args || {},
          error: data.error || data.message || String(data),
          source: data.source || 'tool'
        })
      } catch (err) {
        log.warn('Auto tool-error lesson extraction failed:', err.message)
      }
    })

    // 监听工具重试事件（重试可能意味着配置或参数问题）
    framework.on('tool:retry', async (data) => {
      try {
        const { name, args, error, attempt } = data
        await this._extractErrorLesson({
          name: name || 'unknown-tool',
          args: args || {},
          error: `Retry attempt ${attempt} failed: ${error || data.message || 'unknown'}`,
          source: 'tool-retry'
        })
      } catch (err) {
        log.warn('Auto tool retry lesson extraction failed:', err.message)
      }
    })

    // 监听 agent 对话过程中的错误
    framework.on('error', async (data) => {
      try {
        const errorObj = typeof data === 'object' ? data : { error: String(data) }
        await this._extractErrorLesson({
          name: errorObj.context || 'agent-error',
          args: errorObj.data || {},
          error: errorObj.error || errorObj.message || String(data),
          source: 'agent'
        })
      } catch (err) {
        log.warn('Auto agent error lesson extraction failed:', err.message)
      }
    })

    // 监听 agent status 错误
    framework.on('status', async (data) => {
      if (data.status === 'error' && data.error) {
        try {
          await this._extractErrorLesson({
            name: 'agent-status-error',
            args: {},
            error: data.error,
            source: 'agent-status'
          })
        } catch (err) {
          log.warn('Auto status error lesson extraction failed:', err.message)
        }
      }
    })

    // 监听会话上下文错误
    framework.on('session:context-destroyed', async (data) => {
      // 上下文销毁通常是正常的，但如果有错误信息则记录
      if (data && data.error) {
        try {
          await this._extractErrorLesson({
            name: 'session-context-error',
            args: { sessionId: data.sessionId },
            error: data.error,
            source: 'session'
          })
        } catch (err) {
          log.warn('Auto session error lesson extraction failed:', err.message)
        }
      }
    })
  }

  /**
   * 从错误中提取经验教训并保存
   */
  async _extractErrorLesson(errorData) {
    const { name, args, error, source } = errorData

    // 构建提取提示 - 强调"如何下次避免"
    const extractPrompt = `你是一个经验总结专家。请分析以下错误，总结如何在未来避免类似错误。

错误信息：
- 工具名称: ${name}
- 调用参数: ${JSON.stringify(args)}
- 错误原因: ${error}
- 来源: ${source || 'unknown'}

请按以下格式返回（仅返回 JSON，不要有其他内容）：
{
  "extract": true/false,
  "name": "【避免指南】具体说明避免什么（如：避免不传 plugin 参数调用 ext_call）",
  "tags": ["error", "avoid", "${name}"],
  "content": "以【下次这样做】为开头，说明正确的做法。例如：\n【下次这样做】调用 ext_call 时必须传入 plugin、tool、args 三个参数。错误原因：缺少 plugin 参数导致扩展插件无法定位。"
}

如果错误是无关紧要的（如用户主动取消、超时重试等），返回：
{"extract": false}`

    try {
      const result = await this._runMemoryExtractionAgent(extractPrompt)

      if (result && result.extract === true) {
        try {
          const saved = this._store.add({
            name: result.name,
            type: result.type || MEMORY_TYPES.FEEDBACK,
            project: null,
            tags: result.tags || ['error', 'avoid'],
            body: result.content
          })
        } catch (saveErr) {
          log.warn('[Memory] Failed to save error lesson:', saveErr.message)
        }
      }
    } catch (err) {
      log.warn('[Memory] Error lesson extraction failed:', err.message)
    }
  }

  /**
   * 从对话中提取记忆
   */
  async _extractMemoryFromConversation(userMessage, assistantResponse) {
    // 构建提取提示
    const extractPrompt = `你是一个记忆提取专家。请分析以下对话，提取有价值的信息到记忆系统。

用户消息：
${typeof userMessage === 'string' ? userMessage : JSON.stringify(userMessage)}

助手回复：
${typeof assistantResponse === 'string' ? assistantResponse : JSON.stringify(assistantResponse)}

请分析并决定是否需要提取记忆。记忆类型：
- user: 用户偏好、习惯、设置（如喜欢用 deepseek provider）
- feedback: 用户反馈、建议、批评
- project: 项目相关信息、上下文
- reference: 外部知识、参考资料

如果需要提取，请按以下格式返回（仅返回 JSON，不要有其他内容）：
{
  "extract": true/false,
  "type": "user/feedback/project/reference",
  "name": "记忆名称",
  "project": "项目名（仅 project 类型需要）",
  "tags": ["tag1", "tag2"],
  "content": "要记忆的内容，包含 Why（为什么重要）和 How to apply（如何使用）"
}

如果不需要提取，返回：
{"extract": false}`

    try {
      // 使用 memory-subagent 执行提取（受限工具权限）
      const result = await this._runMemoryExtractionAgent(extractPrompt)

      if (result && result.extract === true) {
        this._store.add({
          name: result.name,
          type: result.type,
          project: result.project || null,
          tags: result.tags || [],
          body: result.content
        })
        log.info(`Auto-extracted memory: ${result.name} (${result.type})`)
      }
    } catch (err) {
      log.warn('Memory extraction agent failed:', err.message)
    }
  }

  /**
   * 运行记忆提取子 agent
   * 使用独立的轻量子 agent 处理记忆提取，不占用主 agent 资源
   */
  async _runMemoryExtractionAgent(prompt) {
    if (!this._memoryAgent) {
      log.warn('Memory extraction: memory sub-agent not found')
      return null
    }

    // 设置提取标志，防止递归调用
    this._isExtracting = true

    try {
      const fullPrompt = `你是一个记忆提取专家。直接返回 JSON 格式的答案，不要输出任何思考过程、解释或其他内容。格式：{"extract":true/false,"name":"...","tags":[...],"content":"..."}

${prompt}`

      const result = await this._memoryAgent.chat(fullPrompt, { maxSteps: 1 })

      // 解析 JSON 响应
      if (result?.message) {
        const cleanedText = cleanResponse(result.message.trim())

        // 移除 markdown 代码块包裹
        let jsonText = cleanedText
        if (jsonText.startsWith('```')) {
          jsonText = jsonText.replace(/^```[\w]*\n?/, '').replace(/\n?```$/, '').trim()
        }

        // 尝试提取并解析 JSON
        const jsonStr = _extractJSON(jsonText)
        if (jsonStr) {
          try {
            const parsed = JSON.parse(jsonStr)
            return parsed
          } catch (parseErr) {
            // JSON 解析失败，尝试清理不可见字符后重试
            const cleaned = jsonStr.replace(/[\u0000-\u001F\u007F-\u009F\u200B-\u200F\u2028\u2029]/g, '')
            try {
              const parsed = JSON.parse(cleaned)
              return parsed
            } catch (e) {
              log.warn('Failed to parse extracted JSON:', jsonStr.substring(0, 200))
            }
          }
        }
      }
    } catch (err) {
      log.warn('Memory extraction agent failed:', err.message)
    } finally {
      // 必须清除提取标志
      this._isExtracting = false
    }

    return null
  }

  /**
   * 注册 memory-context 到系统提示
   */
  _registerMemoryContext(framework) {
    const mainAgent = framework._mainAgent
    if (mainAgent) {
      mainAgent.registerPromptPart('memory-context', 350, () => {
        return this._buildMemoryContext()
      })
      mainAgent._refreshContext()
    }

    framework.on('framework:ready', () => {
      const agent = framework._mainAgent
      if (agent) {
        agent.registerPromptPart('memory-context', 350, () => {
          return this._buildMemoryContext()
        })
        agent._refreshContext()
      }
    })
  }

  /**
   * 设置动态刷新 - 记忆变化时自动刷新系统提示词
   */
  _setupDynamicRefresh(framework) {
    this._store.on('change', ({ action, memory }) => {
      const mainAgent = framework._mainAgent
      if (mainAgent) {
        mainAgent.invalidatePromptPart('memory-context')
        mainAgent._refreshContext()
      }
    })
  }

  /**
   * 构建记忆上下文（注入到系统提示）
   */
  _buildMemoryContext() {
    try {
      const userMemories = this._store.listByType(MEMORY_TYPES.USER, 10)
      const projectMemories = this._store.listByType(MEMORY_TYPES.PROJECT, 5)
      const feedbackMemories = this._store.search('', { type: MEMORY_TYPES.FEEDBACK, tags: ['avoid'], limit: 10 })

      if (userMemories.length === 0 && projectMemories.length === 0 && feedbackMemories.length === 0) {
        return null
      }

      const parts = ['【记忆上下文】']

      // 错误避免指南（优先显示，放在最前面）
      if (feedbackMemories.length > 0) {
        parts.push('【错误避免指南 - 必须遵守】')
        for (const m of feedbackMemories) {
          parts.push(`- ${m.body}`)
        }
      }

      if (userMemories.length > 0) {
        parts.push('【用户偏好】')
        for (const m of userMemories) {
          parts.push(`- ${m.name}: ${m.body.substring(0, 150)}${m.body.length > 150 ? '...' : ''}`)
        }
      }

      if (projectMemories.length > 0) {
        parts.push('【项目上下文】')
        for (const m of projectMemories) {
          const projectTag = m.project ? `[${m.project}] ` : ''
          parts.push(`- ${projectTag}${m.name}: ${m.body.substring(0, 100)}${m.body.length > 100 ? '...' : ''}`)
        }
      }

      return parts.join('\n')
    } catch (err) {
      log.warn('Failed to build memory context:', err.message)
      return null
    }
  }

  /**
   * 获取存储实例（供其他插件使用）
   */
  getStore() {
    return this._store
  }

  /**
   * 搜索记忆（公开 API）
   */
  searchMemories(query, options = {}) {
    return this._store.search(query, options)
  }

  reload(framework) {
    this._framework = framework
    // 重新初始化存储
    this._store = new MemoryStore(this.config.memoryDir)
  }

  uninstall(framework) {
    this._store = null
    this._framework = null
  }
}

module.exports = MemoryPlugin
