/**
 * IndexedDB存储工具类
 * 用于存储大量token数据，突破localStorage的5-10MB限制
 * IndexedDB通常支持几百MB甚至GB的存储空间
 */

const DB_NAME = 'XyzwGameHelper'
const DB_VERSION = 1
const STORE_NAME = 'gameTokens'
const BIN_STORE_NAME = 'binFiles' // bin文件存储

class IndexedDBStorage {
  constructor() {
    this.db = null
    this.initPromise = null
  }

  /**
   * 初始化数据库
   */
  async init() {
    // 如果已经初始化过，直接返回
    if (this.db) {
      return this.db
    }

    // 如果正在初始化，等待初始化完成
    if (this.initPromise) {
      return this.initPromise
    }

    this.initPromise = new Promise((resolve, reject) => {
      const request = indexedDB.open(DB_NAME, DB_VERSION)

      request.onerror = () => {
        console.error('❌ IndexedDB打开失败:', request.error)
        reject(request.error)
      }

      request.onsuccess = () => {
        this.db = request.result
        console.log('✅ IndexedDB初始化成功')
        resolve(this.db)
      }

      request.onupgradeneeded = (event) => {
        const db = event.target.result
        
        // 创建token对象存储
        if (!db.objectStoreNames.contains(STORE_NAME)) {
          const objectStore = db.createObjectStore(STORE_NAME, { keyPath: 'id' })
          
          // 创建索引以便快速查询
          objectStore.createIndex('name', 'name', { unique: false })
          objectStore.createIndex('isActive', 'isActive', { unique: false })
          objectStore.createIndex('lastUsed', 'lastUsed', { unique: false })
          
          console.log('✅ IndexedDB token存储创建成功')
        }
        
        // 创建bin文件对象存储
        if (!db.objectStoreNames.contains(BIN_STORE_NAME)) {
          const binObjectStore = db.createObjectStore(BIN_STORE_NAME, { keyPath: 'id' })
          
          // 创建索引以便快速查询
          binObjectStore.createIndex('fileName', 'fileName', { unique: false })
          binObjectStore.createIndex('lastUsed', 'lastUsed', { unique: false })
          binObjectStore.createIndex('createdAt', 'createdAt', { unique: false })
          
          console.log('✅ IndexedDB bin文件存储创建成功')
        }
      }
    })

    return this.initPromise
  }

  /**
   * 保存所有tokens（全量替换）
   * 注意：这个方法会清空后再添加，适合初始化和迁移，不适合频繁调用
   * @param {Array} tokens - token数组
   */
  async saveTokens(tokens) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      // 清空现有数据
      await new Promise((resolve, reject) => {
        const clearRequest = objectStore.clear()
        clearRequest.onsuccess = () => resolve()
        clearRequest.onerror = () => reject(clearRequest.error)
      })
      
      // 批量添加新数据
      const promises = tokens.map(token => {
        return new Promise((resolve, reject) => {
          const request = objectStore.add(token)
          request.onsuccess = () => resolve()
          request.onerror = () => reject(request.error)
        })
      })
      
      await Promise.all(promises)
      console.log(`✅ 成功保存 ${tokens.length} 个token到IndexedDB`)
      return true
    } catch (error) {
      console.error('❌ 保存tokens到IndexedDB失败:', error)
      throw error
    }
  }

  /**
   * 批量更新tokens（增量更新，性能优化）
   * 使用put而非clear+add，只更新变化的数据
   * @param {Array} tokens - token数组
   */
  async updateTokens(tokens) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      // 使用put批量更新，不清空现有数据
      const promises = tokens.map(token => {
        return new Promise((resolve, reject) => {
          const request = objectStore.put(token)  // put会自动添加或更新
          request.onsuccess = () => resolve()
          request.onerror = () => reject(request.error)
        })
      })
      
      await Promise.all(promises)
      console.log(`✅ 批量更新 ${tokens.length} 个token到IndexedDB`)
      return true
    } catch (error) {
      console.error('❌ 批量更新tokens失败:', error)
      throw error
    }
  }

  /**
   * 获取所有tokens
   */
  async getTokens() {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readonly')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.getAll()
        request.onsuccess = () => {
          console.log(`✅ 从IndexedDB读取了 ${request.result.length} 个token`)
          resolve(request.result)
        }
        request.onerror = () => {
          console.error('❌ 从IndexedDB读取tokens失败:', request.error)
          reject(request.error)
        }
      })
    } catch (error) {
      console.error('❌ 获取tokens失败:', error)
      return []
    }
  }

  /**
   * 添加或更新单个token
   * @param {Object} token - token对象
   */
  async putToken(token) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.put(token)
        request.onsuccess = () => resolve(true)
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 更新token到IndexedDB失败:', error)
      throw error
    }
  }

  /**
   * 删除单个token
   * @param {String} tokenId - token ID
   */
  async deleteToken(tokenId) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.delete(tokenId)
        request.onsuccess = () => resolve(true)
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 从IndexedDB删除token失败:', error)
      throw error
    }
  }

  /**
   * 删除单个token
   * @param {String} tokenId - token ID
   */
  async deleteToken(tokenId) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.delete(tokenId)
        request.onsuccess = () => resolve(true)
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 从IndexedDB删除token失败:', error)
      throw error
    }
  }

  /**
   * 清空所有tokens
   */
  async clearTokens() {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.clear()
        request.onsuccess = () => {
          console.log('✅ 已清空IndexedDB中的所有tokens')
          resolve(true)
        }
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 清空IndexedDB失败:', error)
      throw error
    }
  }

  /**
   * 获取存储的token数量
   */
  async getCount() {
    try {
      await this.init()
      
      const transaction = this.db.transaction([STORE_NAME], 'readonly')
      const objectStore = transaction.objectStore(STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.count()
        request.onsuccess = () => resolve(request.result)
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 获取token数量失败:', error)
      return 0
    }
  }

  /**
   * 获取存储使用情况（估算）
   */
  async getStorageEstimate() {
    if ('storage' in navigator && 'estimate' in navigator.storage) {
      try {
        const estimate = await navigator.storage.estimate()
        return {
          usage: estimate.usage,
          quota: estimate.quota,
          usageMB: (estimate.usage / 1024 / 1024).toFixed(2),
          quotaMB: (estimate.quota / 1024 / 1024).toFixed(2),
          percentUsed: ((estimate.usage / estimate.quota) * 100).toFixed(2)
        }
      } catch (error) {
        console.error('❌ 获取存储估算失败:', error)
        return null
      }
    }
    return null
  }

  // ========== Bin文件存储方法 ==========

  /**
   * 保存单个bin文件
   * @param {Object} binFile - bin文件对象 {id, fileName, content, roleName, lastUsed, createdAt}
   */
  async saveBinFile(binFile) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([BIN_STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(BIN_STORE_NAME)
      
      // 确保有必要的字段
      const binFileData = {
        id: binFile.id,
        fileName: binFile.fileName || 'unknown',
        content: binFile.content,
        roleName: binFile.roleName || '',
        lastUsed: binFile.lastUsed || new Date().toISOString(),
        createdAt: binFile.createdAt || new Date().toISOString()
      }
      
      return new Promise((resolve, reject) => {
        const request = objectStore.put(binFileData)
        request.onsuccess = () => resolve(true)
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 保存bin文件到IndexedDB失败:', error)
      throw error
    }
  }

  /**
   * 批量保存bin文件（性能优化版）
   * 使用单事务批量插入，提速2-3倍
   * @param {Array} binFiles - bin文件数组
   * @param {Function} onProgress - 进度回调 (saved, total, percent)
   */
  async saveBinFiles(binFiles, onProgress = null) {
    try {
      await this.init()
      
      const total = binFiles.length
      
      // ⚡ 优化：分批保存，每批200个（平衡性能和内存）
      const batchSize = 200
      let saved = 0
      
      for (let i = 0; i < total; i += batchSize) {
        const batch = binFiles.slice(i, i + batchSize)
        const batchNum = Math.floor(i / batchSize) + 1
        const totalBatches = Math.ceil(total / batchSize)
        
        // 每批使用独立事务
        const transaction = this.db.transaction([BIN_STORE_NAME], 'readwrite')
        const objectStore = transaction.objectStore(BIN_STORE_NAME)
        
        // ⚡ 关键优化：连续提交put操作，不创建Promise数组
        batch.forEach(binFile => {
          const binFileData = {
            id: binFile.id,
            fileName: binFile.fileName || 'unknown',
            content: binFile.content,
            roleName: binFile.roleName || '',
            lastUsed: binFile.lastUsed || new Date().toISOString(),
            createdAt: binFile.createdAt || new Date().toISOString()
          }
          objectStore.put(binFileData)  // 连续提交，不await
        })
        
        // 等待当前批次的事务完成
        await new Promise((resolve, reject) => {
          transaction.oncomplete = () => resolve()
          transaction.onerror = () => reject(transaction.error)
        })
        
        saved += batch.length
        
        // 进度反馈
        if (onProgress) {
          const percent = ((saved / total) * 100).toFixed(1)
          onProgress(saved, total, percent)
        }
        
        // 每5批或最后一批显示进度
        if (batchNum % 5 === 0 || batchNum === totalBatches) {
          const percent = ((saved / total) * 100).toFixed(1)
          console.log(`  📦 保存进度: ${saved}/${total} (${percent}%) [批次 ${batchNum}/${totalBatches}]`)
        }
      }
      
      console.log(`✅ 成功保存 ${total} 个bin文件到IndexedDB`)
      return true
    } catch (error) {
      console.error('❌ 批量保存bin文件到IndexedDB失败:', error)
      throw error
    }
  }

  /**
   * 获取单个bin文件
   * @param {String} binFileId - bin文件ID
   */
  async getBinFile(binFileId) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([BIN_STORE_NAME], 'readonly')
      const objectStore = transaction.objectStore(BIN_STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.get(binFileId)
        request.onsuccess = () => {
          if (request.result) {
            console.log(`✅ 从IndexedDB读取了bin文件: ${binFileId}`)
          }
          resolve(request.result || null)
        }
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 从IndexedDB读取bin文件失败:', error)
      return null
    }
  }

  /**
   * 获取所有bin文件
   */
  async getAllBinFiles() {
    try {
      await this.init()
      
      const transaction = this.db.transaction([BIN_STORE_NAME], 'readonly')
      const objectStore = transaction.objectStore(BIN_STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.getAll()
        request.onsuccess = () => {
          console.log(`✅ 从IndexedDB读取了 ${request.result.length} 个bin文件`)
          resolve(request.result)
        }
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 获取所有bin文件失败:', error)
      return []
    }
  }

  /**
   * 删除单个bin文件
   * @param {String} binFileId - bin文件ID
   */
  async deleteBinFile(binFileId) {
    try {
      await this.init()
      
      const transaction = this.db.transaction([BIN_STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(BIN_STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.delete(binFileId)
        request.onsuccess = () => {
          console.log(`✅ 从IndexedDB删除了bin文件: ${binFileId}`)
          resolve(true)
        }
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 从IndexedDB删除bin文件失败:', error)
      throw error
    }
  }

  /**
   * 清空所有bin文件
   */
  async clearBinFiles() {
    try {
      await this.init()
      
      const transaction = this.db.transaction([BIN_STORE_NAME], 'readwrite')
      const objectStore = transaction.objectStore(BIN_STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.clear()
        request.onsuccess = () => {
          console.log('✅ 已清空IndexedDB中的所有bin文件')
          resolve(true)
        }
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 清空IndexedDB bin文件失败:', error)
      throw error
    }
  }

  /**
   * 获取bin文件数量
   */
  async getBinFileCount() {
    try {
      await this.init()
      
      const transaction = this.db.transaction([BIN_STORE_NAME], 'readonly')
      const objectStore = transaction.objectStore(BIN_STORE_NAME)
      
      return new Promise((resolve, reject) => {
        const request = objectStore.count()
        request.onsuccess = () => resolve(request.result)
        request.onerror = () => reject(request.error)
      })
    } catch (error) {
      console.error('❌ 获取bin文件数量失败:', error)
      return 0
    }
  }
}

// 创建单例实例
const indexedDBStorage = new IndexedDBStorage()

export default indexedDBStorage

