/**
 * 快捷键管理器
 *
 * 功能：
 * 1. 基于作用域的快捷键隔离 - 不同页面/Tab 的快捷键互不干扰
 * 2. 支持路由级（route:/path）和 Tab 页签级（route:/path:tab:name）作用域
 * 3. 激活状态管理 - 只有激活的作用域中的快捷键才会响应
 *
 * 【核心概念】
 *
 * 作用域（Scope）：
 * - 路由作用域：route:/xxx，标识一个路由页面
 * - Tab 作用域：route:/xxx:tab:name，标识某个 Tab 页签
 *
 * 激活状态：
 * - 每个作用域有激活/停用状态
 * - 快捷键只有在它所属的作用域激活时才能响应
 *
 * 【架构分层】
 *
 * ┌─────────────────────────────────────────────────────────────┐
 * │ shortcutRouterPlugin    ← 路由守卫，管理路由级作用域        │
 * │         ↓                                                   │
 * │ XTab.vue               ← Tab 切换，管理 Tab 级作用域        │
 * │         ↓                                                   │
 * │ shortcutMixin           ← 组件混入，注册/管理组件的快捷键    │
 * │         ↓                                                   │
 * │ shortcutManager        ← 核心管理器，存储快捷键和作用域状态 │
 * └─────────────────────────────────────────────────────────────┘
 *
 * 【快捷键执行链路】
 *
 * 1. 用户按下快捷键
 * 2. document keydown 事件触发
 * 3. shortcutManager.handleKeydown() 处理
 * 4. 标准化按键（ctrl+shift+a）
 * 5. 查找已注册的快捷键
 * 6. 检查快捷键所在作用域是否激活
 * 7. 执行对应的 customFunction
 *
 * 【使用方式】
 *
 * import { shortcutManager } from '@vue2-client/base-client/utils/shortcutManager'
 *
 * // 启用快捷键系统
 * shortcutManager.enable()
 *
 * // 注册快捷键
 * shortcutManager.register({
 *   key: 'ctrl+s',
 *   scope: 'route:/home',
 *   action: { customFunction: 'this.save()' },
 *   context: this
 * })
 *
 * // 激活作用域
 * shortcutManager.setScopeActive('route:/home', true)
 *
 * 【环境变量配置】
 *
 * - VUE_APP_SHORTCUT_ENABLED: 设置为 'true' 时自动启用快捷键功能
 * - 默认不启用，需要主项目显式调用 enable() 方法启用
 */

import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'

// 开发环境日志工具
const log = (env => {
  if (env !== 'development') {
    return () => {}
  }
  return (tag, ...args) => console.log(`[ShortcutManager] [${tag}]`, ...args)
})(process.env.NODE_ENV)

// 检查是否应该根据环境变量自动启用
const shouldAutoEnableByEnv = () => {
  return process.env.VUE_APP_SHORTCUT_ENABLED === 'true'
}

/**
 * 快捷键管理器（单例）
 *
 * 核心数据结构：
 * - shortcuts: Map<key, entries[]>  存储所有注册的快捷键
 * - scopeActive: Map<scope, boolean>  存储作用域的激活状态
 * - scopeStack: string[]  作用域栈，用于嵌套场景
 */
class ShortcutManager {
  constructor() {
    /**
     * 快捷键 Map
     *
     * 结构：Map<标准化后的按键, 快捷键条目[]>
     *
     * 例如：
     * 'ctrl+s' → [
     *   { scope: 'route:/home', action: {...}, context: {...}, isActive: true },
     *   { scope: 'route:/settings', action: {...}, context: {...}, isActive: true }
     * ]
     *
     * 同一个按键可以在不同作用域注册，按下时只会执行当前激活作用域中的快捷键
     */
    this.shortcuts = new Map()

    /**
     * 作用域栈 - 用于管理激活状态
     *
     * 用于支持嵌套的作用域场景（如 Tab 切换）
     * 最近的活跃作用域在栈顶
     */
    this.scopeStack = []

    /**
     * 作用域激活状态 Map
     *
     * 结构：Map<scopeId, isActive>
     *
     * 例如：
     * 'route:/home' → true
     * 'route:/home:tab:tab1' → true
     * 'route:/home:tab:tab2' → false
     *
     * 快捷键只有在它所在的作用域激活时才会响应
     */
    this.scopeActive = new Map()

    /**
     * 路由状态快照 Map
     *
     * 结构：Map<路由路径, { tabStates: Map<Tab作用域, 是否激活>, lastAccess: number }>
     *
     * 用于路由切换时保存/恢复 Tab 作用域状态
     */
    this.routeStateSnapshots = new Map()

    // 绑定键盘事件处理函数（使用 bind 保持 this 引用）
    this.boundHandleKeydown = this.handleKeydown.bind(this)

    // 默认不启用，需要主项目显式调用 enable() 或设置环境变量
    this._enabled = shouldAutoEnableByEnv()

    // 如果环境变量设置为启用，则自动初始化
    if (this._enabled) {
      this.init()
    }
  }

  // ========== 启用/禁用控制 ==========

  /**
   * 检查快捷键系统是否已启用
   *
   * 只有启用后，快捷键才会被注册和响应
   */
  get isEnabled() {
    return this._enabled === true
  }

  /**
   * 启用快捷键系统
   *
   * 由主项目在合适的时机调用（如 Vue 组件的 mounted 中）
   *
   * @param {Object} options 配置选项
   * @param {boolean} options.autoInit 是否自动初始化键盘监听，默认为 true
   *
   * @example
   * // 在 Vue 入口文件中
   * import { shortcutManager } from '@vue2-client/base-client/utils/shortcutManager'
   * shortcutManager.enable()
   */
  enable(options = {}) {
    if (this._enabled) {
      log('warn', '已启用，跳过')
      return
    }

    this._enabled = true

    // 自动初始化
    if (options.autoInit !== false) {
      this.init()
    }

    log('info', '✅ 快捷键系统已启用')
  }

  /**
   * 禁用快捷键系统
   *
   * 禁用后所有快捷键都不会响应
   */
  disable() {
    if (!this._enabled) return
    document.removeEventListener('keydown', this.boundHandleKeydown, true)
    this._enabled = false
    this._initialized = false
    this.shortcuts.clear()
    this.scopeStack = []
    this.scopeActive.clear()
    this.routeStateSnapshots.clear()
  }

  /**
   * 初始化键盘监听
   *
   * 在 document 上添加 keydown 事件监听
   * 使用 capture 模式确保在事件冒泡前捕获
   */
  init() {
    // 未启用时不初始化
    if (!this._enabled) {
      return
    }

    // 防止重复初始化
    if (this._initialized) {
      return
    }

    this._initialized = true

    // 使用 capture 模式：在事件捕获阶段处理，比冒泡更早
    document.addEventListener('keydown', this.boundHandleKeydown, true)

    log('info', '✅ 初始化完成，开始监听 keydown 事件')
  }

  /**
   * 检查是否已就绪
   *
   * 就绪 = 已启用 + 已初始化
   */
  get isReady() {
    return this._initialized === true && this._enabled === true
  }

  /**
   * 销毁
   *
   * 移除事件监听，清空所有数据
   */
  destroy() {
    document.removeEventListener('keydown', this.boundHandleKeydown)
    this.shortcuts.clear()
    this.scopeStack = []
    this.scopeActive.clear()

    log('info', '🗑️ 销毁完成')
  }

  // ========== 作用域管理 ==========

  /**
   * 生成路由级作用域 ID
   *
   * 格式：route:<路由路径>
   * 例如：route:/zhuyuanyishengzhan/residentDoctorStationCover
   *
   * @param {string} routePath 路由路径
   * @returns {string} 作用域 ID
   */
  generateRouteScope(routePath) {
    return `route:${routePath || 'default'}`
  }

  /**
   * 生成 Tab 页签级作用域 ID
   *
   * 格式：route:<路由路径>:tab:<父Tab>/<子Tab>/<孙Tab>
   * 例如：route:/zhuyuanyishengzhan/residentDoctorStationCover:tab:outerTab1/innerTab1/deepestTab
   *
   * @param {string} routePath 路由路径
   * @param {string} tabKey Tab 的完整链路（支持嵌套格式，如 'outer/inner/deep'）
   * @returns {string} 作用域 ID
   */
  generateTabScope(routePath, tabKey) {
    // 如果 tabKey 已经是完整链路（如 'outer/inner'），直接使用
    // 如果只是单个 tab key，则原样使用
    return `route:${routePath || 'default'}:tab:${tabKey}`
  }

  /**
   * 生成带父级链路的 Tab 作用域 ID
   *
   * 用于明确指定父级 Tab 链路
   *
   * @param {string} routePath 路由路径
   * @param {string} parentTabPath 父级 Tab 链路（如 'outerTab' 或 'outerTab/innerTab'）
   * @param {string} currentTabKey 当前 Tab key
   * @returns {string} 作用域 ID
   */
  generateTabScopeWithParent(routePath, parentTabPath, currentTabKey) {
    if (!parentTabPath) {
      return this.generateTabScope(routePath, currentTabKey)
    }
    const fullPath = `${parentTabPath}/${currentTabKey}`
    return `route:${routePath || 'default'}:tab:${fullPath}`
  }

  /**
   * 设置作用域激活状态
   *
   * 这是核心方法，用于：
   * - 路由切换时激活/停用路由作用域
   * - Tab 切换时激活/停用 Tab 作用域
   * - 组件激活/停用时管理作用域状态
   *
   * 注意：只设置状态，不会自动执行快捷键
   *
   * @param {string} scopeId 作用域 ID
   * @param {boolean} active 是否激活
   *
   * @example
   * // 进入页面时激活
   * shortcutManager.setScopeActive('route:/home', true)
   *
   * // 离开页面时停用
   * shortcutManager.setScopeActive('route:/home', false)
   */
  setScopeActive(scopeId, active) {
    if (!this._enabled) return

    const wasActive = this.scopeActive.get(scopeId)
    this.scopeActive.set(scopeId, active)

    // 仅在状态变化时记录日志
    if (wasActive !== active) {
      log('scope', `${active ? '✅' : '❌'} ${active ? '激活' : '停用'}作用域: ${scopeId}`)
    }
  }

  // ========== 路由状态保存/恢复 ==========

  /**
   * 保存路由的所有 Tab 作用域状态
   *
   * 路由切换时调用，保存当前路由下所有 Tab 作用域的激活状态。
   * 恢复时会自动还原所有已激活的 Tab 状态。
   *
   * @param {string} routePath 路由路径
   * @returns {number} 保存的作用域数量
   */
  saveRouteState(routePath) {
    if (!routePath) return 0

    const routePrefix = `route:${routePath}:tab:`
    const tabStates = new Map()

    this.scopeActive.forEach((isActive, scopeId) => {
      if (scopeId.startsWith(routePrefix)) {
        tabStates.set(scopeId, isActive)
      }
    })

    console.log(`[ShortcutManager saveRouteState] 路由=${routePath}`)
    console.log(`[ShortcutManager saveRouteState] 保存前 scopeActive 中该路由的 Tab:`)
    this.scopeActive.forEach((isActive, scopeId) => {
      if (scopeId.startsWith(routePrefix)) {
        console.log(`  ${isActive ? '✅' : '❌'} ${scopeId}`)
      }
    })
    console.log(`[ShortcutManager saveRouteState] 共 ${tabStates.size} 个 Tab 作用域`)

    if (tabStates.size > 0) {
      this.routeStateSnapshots.set(routePath, {
        tabStates,
        lastAccess: Date.now()
      })
      log('route', `💾 保存路由状态: ${routePath}，${tabStates.size} 个 Tab 作用域`)
    } else {
      // saveRouteState 的 else 分支（没有 Tab 作用域时）
      const existing = this.routeStateSnapshots.get(routePath)
      if (!existing) {
        this.routeStateSnapshots.set(routePath, {
          tabStates: new Map(),
          tabActiveKeys: {},       // ← 加上这一行
          lastAccess: Date.now()
        })
      }
    }

    return tabStates.size
  }

  saveRouteActiveKey(routePath, activeKey, tabInstanceKey = '') {
    console.log('==>routePath',routePath,'activeKey',activeKey,'tabInstanceKey',tabInstanceKey)
    if (!routePath) return

    let snapshot = this.routeStateSnapshots.get(routePath)

    if (!snapshot) {
      snapshot = {
        tabStates: new Map(),
        tabActiveKeys: {},
        lastAccess: Date.now()
      }
    } else {
      if (!snapshot.tabActiveKeys) {
        snapshot.tabActiveKeys = {}
      }
      snapshot.lastAccess = Date.now()
    }

    snapshot.tabActiveKeys[tabInstanceKey] = activeKey

    // 关键：重新 set 回 Map，确保引用更新
    this.routeStateSnapshots.set(routePath, snapshot)

    console.log(`[saveRouteActiveKey] 保存: ${routePath} -> ${tabInstanceKey} = ${activeKey}`)
  }

  /**
   * 获取路由保存的 activeKey
   *
   * @param {string} routePath 路由路径
   * @param {string} tabInstanceKey Tab 实例的唯一标识
   * @returns {number|null} 保存的 activeKey
   */
  getRouteActiveKey(routePath, tabInstanceKey = '') {
    const snapshot = this.routeStateSnapshots.get(routePath)
    if (!snapshot || !snapshot.tabActiveKeys) return null
    return snapshot.tabActiveKeys[tabInstanceKey] ?? null
  }

  /**
   * 恢复路由的 Tab 作用域状态
   *
   * 路由返回时调用，自动恢复所有之前保存的 Tab 激活状态。
   *
   * @param {string} routePath 路由路径
   * @returns {Object|null} 恢复的信息 { tabCount, activatedCount }
   */
  restoreRouteState(routePath) {
    if (!routePath) return null

    console.log(`[ShortcutManager restoreRouteState] 路由=${routePath}`)

    const snapshot = this.routeStateSnapshots.get(routePath)
    if (!snapshot || !snapshot.tabStates || snapshot.tabStates.size === 0) {
      log('route', `📭 无保存的路由状态: ${routePath}`)
      return null
    }

    console.log(`[ShortcutManager restoreRouteState] 快照中保存的 Tab:`)
    snapshot.tabStates.forEach((wasActive, scopeId) => {
      console.log(`  ${wasActive ? '✅' : '❌'} ${scopeId}`)
    })

    // 恢复时更新 lastAccess
    snapshot.lastAccess = Date.now()

    // 直接恢复所有保存的 Tab 激活状态
    let activatedCount = 0
    snapshot.tabStates.forEach((wasActive, scopeId) => {
      const prevActive = this.scopeActive.get(scopeId)
      this.scopeActive.set(scopeId, wasActive)
      if (wasActive !== prevActive) {
        console.log(`[ShortcutManager restoreRouteState] ${wasActive ? '✅' : '❌'} 恢复 ${scopeId} (wasActive=${wasActive}, prev=${prevActive})`)
      }
      if (wasActive) {
        activatedCount++
      }
    })

    log('route', `♻️ 恢复路由状态: ${routePath}，${snapshot.tabStates.size} 个 Tab，${activatedCount} 个已激活`)

    return { tabCount: snapshot.tabStates.size, activatedCount }
  }

  /**
   * 清除路由状态快照
   *
   * @param {string} routePath 路由路径
   * @param {boolean} force 是否强制清除（即使路由还活跃）
   * @returns {boolean} 是否成功清除
   */
  clearRouteState(routePath, force = false) {
    if (!routePath) return false

    // 非强制模式下，检查该路由是否还有活跃的作用域
    if (!force) {
      const routeScope = `route:${routePath}`
      // 如果路由作用域还活跃，不允许清除（可能用户会切回来）
      if (this.scopeActive.get(routeScope) === true) {
        log('route', `⚠️ 跳过清除，路由 ${routePath} 仍处于活跃状态`)
        return false
      }
    }

    if (this.routeStateSnapshots.has(routePath)) {
      this.routeStateSnapshots.delete(routePath)
      log('route', `🗑️ 清除路由状态快照: ${routePath}${force ? ' (强制)' : ''}`)
      return true
    }
    return false
  }

  /**
   * 清理不再活跃的路由状态
   *
   * ⚠️ 注意：默认情况下，只清理完全不被快照引用的作用域。
   * 快照本身不会被自动清理（除非路由从快照中移除）。
   *
   * @param {Object} options 清理选项
   * @param {boolean} [options.preserveAllSnapshots=true] 是否保留所有快照引用的作用域
   * @returns {number} 清理的作用域数量
   */
  cleanupInactiveScopes(options = {}) {
    const { preserveAllSnapshots = true } = options
    let cleanedCount = 0

    // 标记需要保留的作用域
    const scopesToKeep = new Set()

    if (preserveAllSnapshots) {
      // 保留所有快照引用的作用域
      this.routeStateSnapshots.forEach((snapshot, routePath) => {
        snapshot.tabStates?.forEach((_, scopeId) => {
          scopesToKeep.add(scopeId)
        })
        // 保留路由作用域本身
        scopesToKeep.add(`route:${routePath}`)
      })
    }

    // 清理不在保留列表中的非活跃作用域
    const scopesToDelete = []
    this.scopeActive.forEach((isActive, scopeId) => {
      if (!isActive && !scopesToKeep.has(scopeId)) {
        scopesToDelete.push(scopeId)
      }
    })

    scopesToDelete.forEach(scopeId => {
      this.scopeActive.delete(scopeId)
      cleanedCount++
    })

    if (cleanedCount > 0) {
      log('scope', `🧹 清理了 ${cleanedCount} 个非活跃作用域`)
    }

    return cleanedCount
  }

  /**
   * 清理旧路由的状态快照
   *
   * ⚠️ 注意：默认情况下，快照会一直保留以确保路由返回时能恢复状态。
   * 只有在显式调用此方法时才会清理。
   *
   * @param {Object} options 清理选项
   * @param {Function} [options.filter] 过滤器函数，返回 true 表示要删除该快照
   * @param {number} [options.maxSnapshots] 最大快照数量（超过时按访问时间从旧到新删除）
   * @param {string[]} [options.excludeRoutes] 排除的路由列表，这些路由的快照不会被清理
   * @returns {number} 清理的快照数量
   *
   * @example
   * // 清理除了当前活跃路由外的所有快照
   * shortcutManager.cleanupOldRouteSnapshots({
   *   filter: (routePath, snapshot) => routePath !== currentRoute
   * })
   *
   * // 限制最多保留 20 个快照
   * shortcutManager.cleanupOldRouteSnapshots({ maxSnapshots: 20 })
   */
  cleanupOldRouteSnapshots(options = {}) {
    const {
      filter = null,
      maxSnapshots = Infinity,
      excludeRoutes = []
    } = options

    let snapshots = Array.from(this.routeStateSnapshots.entries())

    // 应用过滤器
    if (filter) {
      snapshots = snapshots.filter(([path, snapshot]) => !filter(path, snapshot))
    }

    // 排除指定路由
    snapshots = snapshots.filter(([path]) => !excludeRoutes.includes(path))

    // 超过最大数量时，按最后访问时间从旧到新删除
    if (snapshots.length > maxSnapshots) {
      snapshots.sort((a, b) => (a[1].lastAccess || 0) - (b[1].lastAccess || 0))
      snapshots = snapshots.slice(0, maxSnapshots)
    }

    // 删除不在保留列表中的快照
    const keepPaths = new Set(snapshots.map(([path]) => path))
    let cleanedCount = 0

    this.routeStateSnapshots.forEach((_, routePath) => {
      if (!keepPaths.has(routePath)) {
        this.routeStateSnapshots.delete(routePath)
        cleanedCount++
      }
    })

    if (cleanedCount > 0) {
      log('route', `🧹 清理了 ${cleanedCount} 个路由快照，保留 ${this.routeStateSnapshots.size} 个`)
    }

    return cleanedCount
  }

  /**
   * 完整清理（便捷方法）
   *
   * ⚠️ 注意：默认情况下快照会一直保留。
   * 只有在明确需要释放内存时才调用此方法。
   *
   * @param {Object} options 清理选项
   * @param {boolean} [options.cleanupScopes=true] 是否清理孤立的作用域
   * @param {number} [options.maxSnapshots] 快照数量上限（超过时按访问时间清理）
   * @param {string[]} [options.excludeRoutes] 排除的路由列表
   * @returns {Object} 清理结果
   */
  cleanup(options = {}) {
    const {
      cleanupScopes = true,
      maxSnapshots = Infinity,
      excludeRoutes = []
    } = options

    const results = {}

    if (cleanupScopes) {
      results.inactiveScopes = this.cleanupInactiveScopes({ preserveAllSnapshots: true })
    }

    if (maxSnapshots < Infinity || excludeRoutes.length > 0) {
      results.oldSnapshots = this.cleanupOldRouteSnapshots({ maxSnapshots, excludeRoutes })
    }

    return results
  }

  /**
   * 获取统计信息（用于调试和监控）
   *
   * @returns {Object} 统计信息
   */
  getStats() {
    return {
      shortcutsCount: this.shortcuts.size,
      scopeActiveCount: this.scopeActive.size,
      routeSnapshotsCount: this.routeStateSnapshots.size,
      scopeStackLength: this.scopeStack.length,
      enabled: this._enabled,
      initialized: this._initialized
    }
  }

  /**
   * 获取指定路由下所有 Tab 作用域
   *
   * @param {string} routePath 路由路径
   * @returns {string[]} Tab 作用域 ID 数组
   */
  getRouteTabScopes(routePath) {
    if (!routePath) return []

    const routePrefix = `route:${routePath}:tab:`
    const scopes = []

    this.scopeActive.forEach((_, scopeId) => {
      if (scopeId.startsWith(routePrefix)) {
        scopes.push(scopeId)
      }
    })

    return scopes
  }

  /**
   * 进入作用域（入栈并激活）
   *
   * @param {string} scopeId 作用域 ID
   */
  pushScope(scopeId) {
    if (!this.scopeStack.includes(scopeId)) {
      this.scopeStack.push(scopeId)
    }
    this.setScopeActive(scopeId, true)
  }

  /**
   * 离开作用域（出栈并停用）
   *
   * @returns {string} 被停用的作用域 ID
   */
  popScope() {
    const scopeId = this.scopeStack.pop()
    if (scopeId) {
      this.setScopeActive(scopeId, false)
    }
    return scopeId
  }

  /**
   * 获取当前活跃的作用域
   *
   * @returns {string} 作用域 ID
   */
  getCurrentScope() {
    return this.scopeStack[this.scopeStack.length - 1]
  }

  /**
   * 检查作用域是否激活
   *
   * 快捷键只有在激活的作用域中才能响应
   *
   * @param {string} scopeId 作用域 ID
   * @returns {boolean} 是否激活
   */
  isScopeActive(scopeId) {
    return this.scopeActive.get(scopeId) === true
  }

  // ========== 快捷键注册/注销 ==========

  /**
   * 注册快捷键
   *
   * 将快捷键注册到指定作用域
   *
   * @param {Object} options 注册选项
   * @param {string} options.key - 快捷键，如 'ctrl+enter'
   * @param {Object} options.action - 事件配置（包含 customFunction 等）
   * @param {string} options.scope - 作用域 ID
   * @param {Object} options.context - 执行上下文（组件实例）
   * @param {string} options.cellRef - 组件引用（用于查找组件）
   * @param {boolean} [options.isActive=true] - 快捷键自身是否激活
   * @param {string} options.instanceId - 组件实例 ID（用于区分不同组件）
   *
   * @example
   * shortcutManager.register({
   *   key: 'ctrl+s',
   *   action: { customFunction: 'function(){ this.save() }' },
   *   scope: 'route:/home:tab:tab1',
   *   context: this,
   *   cellRef: 'saveButton',
   *   instanceId: 'comp-123'
   * })
   */
  register({ key, action, scope, context, cellRef, isActive = true, instanceId }) {
    if (!this._enabled) return  // ✅ 加这行

    // 参数校验
    if (!key || !action) return

    const normalizedKey = this.normalizeKey(key)
    if (!normalizedKey) return

    const entry = {
      action, scope, context, cellRef, isActive, instanceId, key,
      registeredAt: Date.now()
    }

    // 避免重复注册
    if (this.shortcuts.has(normalizedKey)) {
      const entries = this.shortcuts.get(normalizedKey)
      const existingIndex = entries.findIndex(e => e.scope === scope && e.cellRef === cellRef)
      if (existingIndex >= 0) return
      entries.push(entry)
    } else {
      this.shortcuts.set(normalizedKey, [entry])
    }

    // 如果所属路由已激活，自动激活这个新注册的作用域
    if (isActive) {
      const routePrefix = scope.split('::')[0] + '::'
      if (this.scopeActive.get(routePrefix)) {
        this.scopeActive.set(scope, true)
      }
    }

    log('reg', `✅ 注册 ${key} → scope=${scope} cellRef=${cellRef || '-'}`)
  }

  /**
   * 注销快捷键
   *
   * 从指定作用域移除快捷键
   *
   * @param {string} key 快捷键
   * @param {string} scope 作用域 ID
   */
  unregister(key, scope) {
    const normalizedKey = this.normalizeKey(key)
    if (!normalizedKey) return

    const entries = this.shortcuts.get(normalizedKey)
    if (!entries) return

    // 过滤掉指定作用域的条目
    const filtered = entries.filter(e => e.scope !== scope)
    if (filtered.length > 0) {
      this.shortcuts.set(normalizedKey, filtered)
    } else {
      this.shortcuts.delete(normalizedKey)
    }

    log('reg', `❌ 注销 ${key} ← scope=${scope}`)
  }

  /**
   * 清空某个作用域下的所有快捷键
   *
   * @param {string} scopeId 作用域 ID
   */
  clearScope(scopeId) {
    for (const [key, entries] of this.shortcuts) {
      const filtered = entries.filter(e => e.scope !== scopeId)
      if (filtered.length > 0) {
        this.shortcuts.set(key, filtered)
      } else {
        this.shortcuts.delete(key)
      }
    }

    log('scope', `🗑️ 清空作用域: ${scopeId}`)
  }

  /**
   * 清空某个组件实例注册的所有快捷键
   *
   * 用于组件销毁时清理其注册的快捷键
   * 注意：不会影响其他组件注册的同名快捷键
   *
   * @param {string} instanceId 组件实例 ID
   */
  clearInstance(instanceId) {
    if (!instanceId) return

    let clearedCount = 0
    for (const [key, entries] of this.shortcuts) {
      const originalLength = entries.length
      const filtered = entries.filter(e => e.instanceId !== instanceId)
      if (filtered.length > 0) {
        this.shortcuts.set(key, filtered)
      } else {
        this.shortcuts.delete(key)
      }
      clearedCount += originalLength - filtered.length
    }

    log('scope', `🗑️ 清空实例 ${instanceId} 的 ${clearedCount} 个快捷键`)
  }

  // ========== 键盘事件处理 ==========

  /**
   * 键盘事件处理
   *
   * 这是快捷键响应的入口
   *
   * 执行链路：
   * 1. 用户按下键盘
   * 2. 标准化按键（如 ctrl+a → 'ctrl+a'）
   * 3. 查找对应的快捷键条目
   * 4. 检查作用域是否激活
   * 5. 执行快捷键的 action
   *
   * @param {KeyboardEvent} e 键盘事件
   */
  handleKeydown(e) {
    // 标准化按键
    const normalizedKey = this.normalizeKey(e)
    if (!normalizedKey) {
      return
    }

    // 查找注册的快捷键
    const entries = this.shortcuts.get(normalizedKey)
    if (!entries || entries.length === 0) {
      return
    }

    // 找到匹配的快捷键，阻止浏览器默认行为
    // 例如：Ctrl+S 默认是保存页面，我们要拦截它
    e.preventDefault()
    e.stopPropagation()

    let executed = false

    // 遍历所有匹配的快捷键
    // 同一按键可以在不同作用域注册（如 Ctrl+S 在不同 Tab 中）
    for (const entry of entries) {
      // 检查作用域是否激活
      const scopeIsActive = this.isScopeActive(entry.scope)

      // 如果作用域未激活或快捷键自身被禁用，跳过
      if (!scopeIsActive || entry.isActive === false) {
        continue
      }

      // 执行快捷键
      this.executeEvent(entry, e)
      executed = true
    }

    if (executed) {
      log('exec', `▶️ 执行 ${normalizedKey} (匹配 ${entries.length} 个)`)
    }
  }

  /**
   * 执行快捷键事件
   *
   * 调用快捷键配置的 customFunction
   *
   * @param {Object} entry 快捷键条目
   * @param {KeyboardEvent} keyboardEvent 原始键盘事件
   */
  executeEvent(entry, keyboardEvent) {
    const { action, context, key } = entry
    if (!action?.customFunction) return

    try {
      executeStrFunctionByContext(context, action.customFunction, [keyboardEvent, key])
    } catch (err) {
      log('error', `❌ 执行失败: ${err.message}`)
    }
  }

  /**
   * 标准化快捷键
   *
   * 将 KeyboardEvent 转换为统一格式
   *
   * 输入示例：
   * - e.key = 's', e.ctrlKey = true → 'ctrl+s'
   * - e.key = 'Enter' → 'enter'
   * - e.key = ' ' → 'space'
   *
   * @param {KeyboardEvent|string} e 键盘事件或字符串
   * @returns {string|null} 标准化后的按键，或 null（忽略修饰键单独按下）
   */
  normalizeKey(e) {
    // 如果是字符串（手动指定按键），直接标准化
    if (typeof e === 'string') {
      return e.toLowerCase().replace(/\s+/g, '').trim()
    }

    // 从 KeyboardEvent 构建按键
    const parts = []
    if (e.ctrlKey) parts.push('ctrl')
    if (e.altKey) parts.push('alt')
    if (e.shiftKey) parts.push('shift')
    if (e.metaKey) parts.push('meta')

    let key = e.key

    // 标准化特殊键
    if (key === ' ') key = 'space'
    if (key === 'Enter') key = 'enter'
    if (key === 'Escape') key = 'esc'
    if (key === 'ArrowUp') key = 'up'
    if (key === 'ArrowDown') key = 'down'
    if (key === 'ArrowLeft') key = 'left'
    if (key === 'ArrowRight') key = 'right'

    key = key.toLowerCase()

    // 忽略修饰键单独按下（防止按住 Ctrl 时触发快捷键）
    if (['control', 'alt', 'shift', 'meta'].includes(key)) return null

    parts.push(key)
    return parts.join('+')
  }

  // ========== 调试工具 ==========

  /**
   * 列出所有快捷键（调试用）
   *
   * @returns {Array} 快捷键信息列表
   */
  listAll() {
    const result = []
    for (const [key, entries] of this.shortcuts) {
      for (const entry of entries) {
        result.push({
          key,
          scope: entry.scope,
          isActive: entry.isActive,
          scopeActive: this.isScopeActive(entry.scope),
          cellRef: entry.cellRef,
          registeredAt: entry.registeredAt
        })
      }
    }
    return result
  }

  /**
   * 获取快捷键信息
   *
   * @param {string} key 快捷键
   * @returns {Array} 快捷键条目列表
   */
  getShortcutInfo(key) {
    const normalizedKey = this.normalizeKey(key)
    return this.shortcuts.get(normalizedKey) || []
  }

  /**
   * 清除路由的 activeKey
   *
   * @param {string} routePath 路由路径
   * @param {string} tabInstanceKey Tab 实例的唯一标识
   */
  clearRouteActiveKey(routePath, tabInstanceKey = '') {
    const snapshot = this.routeStateSnapshots.get(routePath)
    if (!snapshot || !snapshot.tabActiveKeys) return

    delete snapshot.tabActiveKeys[tabInstanceKey]

    // 如果 tabActiveKeys 为空，也清除整个快照（可选）
    if (Object.keys(snapshot.tabActiveKeys).length === 0) {
      // 保留快照但清空 tabActiveKeys，因为可能还有其他数据（如 tabStates）
    }
  }

  /**
   * 调试：打印所有快捷键状态
   *
   * 调用方式：在浏览器控制台执行
   * > window.__shortcutManager.debug()
   *
   * 或在代码中调用
   * > import { shortcutManager } from '@vue2-client/base-client/utils/shortcutManager'
   * > shortcutManager.debug()
   */
  debug() {
    console.log('='.repeat(60))
    console.log('[ShortcutManager] 📋 快捷键状态调试')
    console.log(`系统启用: ${this._enabled ? '✅' : '❌'} | 初始化: ${this._initialized ? '✅' : '❌'}`)
    console.log('='.repeat(60))

    const all = this.listAll()
    console.log(`快捷键总数: ${all.length}`)

    if (all.length === 0) {
      console.log('(暂无快捷键)')
    } else {
      all.forEach((item, index) => {
        console.log(`${index + 1}. ${item.key}`)
        console.log(`   scope: ${item.scope}`)
        console.log(`   cellRef: ${item.cellRef || '-'}`)
        console.log(`   作用域激活: ${item.scopeActive ? '✅' : '❌'} | 快捷键激活: ${item.isActive ? '✅' : '❌'}`)
      })
    }

    console.log('='.repeat(60))
    console.log('作用域激活状态:')
    if (this.scopeActive.size === 0) {
      console.log('(暂无作用域)')
    } else {
      for (const [scope, active] of this.scopeActive) {
        console.log(`  ${active ? '✅' : '❌'} ${scope}`)
      }
    }
    console.log('='.repeat(60))
    // 打印当前快照内容
    console.log('routeStateSnapshots',this.routeStateSnapshots)
  }
}

// 创建单例
export const shortcutManager = new ShortcutManager()

// 挂载到 window 方便调试
window.__shortcutManager = shortcutManager

export default shortcutManager
