// src/utils/imageCacheManager.js
import { IMAGE_CACHE_VERSION } from '@/config/imageCacheVersion'

class ImageCacheManager {
  constructor() {
    this.cacheVersionKey = 'h5_app_version'
    this.currentAppVersion = import.meta.env.VITE_APP_VERSION || '1.0.0'
    this.currentImageVersion = IMAGE_CACHE_VERSION.version // 使用完整版本号
    // 移除了 this.versionType = import.meta.env.VITE_VERSION_TYPE || 'patch'

    this.imageCacheName = `likei-images-v${this.currentImageVersion}` // OSS图片
    this.assetCacheName = `likei-assets-v${this.currentImageVersion}` // 本地assets

    this.maxCacheItems = 100 // 最大缓存数量（100张）
    this.maxCacheSize = 100 * 1024 * 1024 // 最大缓存大小（100MB）

    this.pendingRequests = new Map() // 请求去重的关键

    this.init()
  }

  // 解析版本号为数组 [major, minor, patch]
  parseVersion(version) {
    return version.split('.').map(Number)
  }

  // 比较两个版本号，返回是否版本发生了变化（任何部分的变化）
  isVersionChanged(cachedVersion, currentVersion) {
    return cachedVersion !== currentVersion
  }

  // 检查是否是major版本更新
  isMajorVersionUpdate(cachedVersion, currentVersion) {
    const [cachedMajor] = this.parseVersion(cachedVersion)
    const [currentMajor] = this.parseVersion(currentVersion)
    return currentMajor > cachedMajor
  }

  // 返回对应的缓存
  async getCacheForUrl(url) {
    // 规范化 URL
    const normalizedUrl = this.normalizeUrl(url)

    let cacheName
    if (
      normalizedUrl.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5') ||
      normalizedUrl.includes('/oss/h5/')
    ) {
      cacheName = this.imageCacheName
    } else if (normalizedUrl.includes('/assets/')) {
      cacheName = this.assetCacheName
    } else {
      // 其他外部链接放入通用图片缓存
      cacheName = this.imageCacheName
    }

    try {
      return await caches.open(cacheName)
    } catch (error) {
      console.error(`打开缓存失败: ${cacheName}`, error)
      throw error
    }
  }

  // 选择性清除缓存
  async clearCacheSelective(clearType = 'images') {
    if (!('caches' in window)) return

    try {
      const cacheNames = await caches.keys()
      let cachesToClear = []

      switch (clearType) {
        case 'images':
          cachesToClear = cacheNames.filter((name) => name.startsWith('likei-images-v'))
          break
        case 'assets':
          cachesToClear = cacheNames.filter((name) => name.startsWith('likei-assets-v'))
          break
        case 'all':
          // 清除所有相关缓存（除了动态内容）
          cachesToClear = cacheNames.filter(
            (name) => name.startsWith('likei-images-v') || name.startsWith('likei-assets-v')
          )
          break
        default:
          // 默认只清除图片缓存
          cachesToClear = cacheNames.filter((name) => name.startsWith('likei-images-v'))
      }

      // 等待所有清除操作完成
      await Promise.all(cachesToClear.map((name) => caches.delete(name)))
    } catch (error) {
      console.warn('清理缓存失败:', error)
    }
  }

  async init() {
    await this.checkVersionAndUpdate()
  }

  // 版本检查逻辑
  async checkVersionAndUpdate() {
    const cachedVersion = localStorage.getItem(this.cacheVersionKey)
    const cachedImageVersion = localStorage.getItem('likei-image-version')

    if (!cachedVersion) {
      // 首次安装：保存当前版本和图片版本
      localStorage.setItem(this.cacheVersionKey, this.currentAppVersion)
      localStorage.setItem('likei-image-version', IMAGE_CACHE_VERSION.version)
      return
    }

    // 检查是否是major版本更新
    const isMajorUpdate = this.isMajorVersionUpdate(cachedVersion, this.currentAppVersion)

    // major版本更新：清除所有缓存
    if (isMajorUpdate) {
      console.log(`major版本更新：清除所有缓存`)
      await this.clearAllCaches()
    }

    // 非major版本更新：检查图片版本是否变化
    else {
      const isImageVersionChanged = this.isVersionChanged(
        cachedImageVersion || '1.0.0',
        IMAGE_CACHE_VERSION.version
      )

      // 图片版本变化：根据配置清除指定类型的缓存
      if (isImageVersionChanged) {
        console.log(`非major版本更新：清除缓存类型: ${IMAGE_CACHE_VERSION.cacheType}`)
        await this.clearCacheByType(IMAGE_CACHE_VERSION.cacheType)
      }
      // 如果图片版本未变化且不是major更新，则不执行任何清除操作
    }

    // 更新版本号
    localStorage.setItem(this.cacheVersionKey, this.currentAppVersion)
    localStorage.setItem('likei-image-version', IMAGE_CACHE_VERSION.version)
  }

  // 根据类型清除缓存
  async clearCacheByType(cacheType) {
    switch (cacheType) {
      case 'images':
        await this.clearOldImageCaches()
        break
      case 'assets':
        await this.clearOldAssetCaches()
        break
      case 'all':
        await this.clearAllCaches()
        break
      default:
        // 默认清除全部图片缓存
        await this.clearAllCaches()
        break
    }
  }

  // 检查并清理超出限制的缓存
  async enforceCacheLimits(cache) {
    try {
      const keys = await cache.keys()

      // 检查数量限制
      if (keys.length <= this.maxCacheItems) {
        // 快速估算大小检查（基于headers）
        let estimatedTotalSize = 0
        let needDetailedCheck = false

        // 计算缓存大小
        for (const key of keys) {
          const response = await cache.match(key)
          if (response) {
            const contentLength = response.headers.get('content-length')
            if (contentLength) {
              estimatedTotalSize += parseInt(contentLength, 10)
            } else {
              // 如果有任何一项没有content-length头，需要详细检查
              needDetailedCheck = true
              break
            }
          }
        }

        // 检查大小限制
        // 无需检查，亦或是缓存数量和大小都符合要求，直接返回
        if (!needDetailedCheck && estimatedTotalSize <= this.maxCacheSize) {
          return
        }
      }

      // 缓存项超出限制，需要清理
      // 获取所有缓存项及其大小信息
      const cacheEntries = []
      for (const key of keys) {
        try {
          const response = await cache.match(key)
          if (response) {
            const blob = await response.blob()
            cacheEntries.push({
              key,
              size: blob.size,
              response,
            })
          }
        } catch (e) {
          console.warn('无法获取缓存项大小:', key.url)
        }
      }

      // 计算当前总数和总大小
      let totalItems = cacheEntries.length //当前总数
      let totalSize = cacheEntries.reduce((sum, entry) => sum + entry.size, 0) //总大小

      let itemsToRemoveCount = Math.max(0, totalItems - this.maxCacheItems) // 需要删除的项数
      let sizeToRemove = Math.max(0, totalSize - this.maxCacheSize) // 需要删除的项数

      let itemsToDelete = [] //需要删除的项
      // 综合两个限制条件，确定实际需要删除的项
      if (itemsToRemoveCount > 0 || sizeToRemove > 0) {
        // 按照最旧的顺序排序（keys已经是按顺序的）
        // 逐个删除直到满足两个条件
        let removedSize = 0
        let removedCount = 0

        for (const entry of cacheEntries) {
          // 如果已经满足两个条件，则停止删除
          if (removedCount >= itemsToRemoveCount && totalSize - removedSize <= this.maxCacheSize) {
            break
          }

          itemsToDelete.push(entry.key)
          removedSize += entry.size
          removedCount++
        }
      }

      // 执行删除操作
      for (const key of itemsToDelete) {
        await cache.delete(key)
      }
    } catch (error) {
      console.warn('检查缓存限制时出错:', error)
    }
  }

  // 清除旧的OSS图片缓存
  async clearOldImageCaches() {
    if (!('caches' in window)) return

    try {
      const cacheNames = await caches.keys()
      const oldImageCaches = cacheNames.filter(
        (name) =>
          name.startsWith('likei-images-v') && !name.includes(`v${this.currentImageVersion}`) // 排除当前版本的缓存
      )

      console.log('正在清除旧的OSS图片缓存:', oldImageCaches)
      await Promise.all(oldImageCaches.map((name) => caches.delete(name)))
    } catch (error) {
      console.warn('清理旧的OSS图片缓存失败:', error)
    }
  }

  // 清除旧的本地assets缓存
  async clearOldAssetCaches() {
    if (!('caches' in window)) return

    try {
      const cacheNames = await caches.keys()
      const oldAssetCaches = cacheNames.filter(
        (name) =>
          name.startsWith('likei-assets-v') && !name.includes(`v${this.currentImageVersion}`) // 排除当前版本的缓存
      )

      console.log('正在清除旧的本地assets缓存:', oldAssetCaches)
      await Promise.all(oldAssetCaches.map((name) => caches.delete(name)))
    } catch (error) {
      console.warn('清理旧的本地assets缓存失败:', error)
    }
  }

  // 清除所有图片缓存（OSS图片、本地assets图片）
  async clearAllCaches() {
    if (!('caches' in window)) return

    try {
      const cacheNames = await caches.keys()
      const allCaches = cacheNames.filter(
        (name) => name.startsWith('likei-images-v') || name.startsWith('likei-assets-v')
      )

      console.log('正在清除所有图片缓存:', allCaches)
      await Promise.all(allCaches.map((name) => caches.delete(name)))
    } catch (error) {
      console.warn('清理所有图片缓存失败:', error)
    }
  }

  // 判断是否为适合缓存资源
  isBuildAsset(url) {
    try {
      // 规范化 URL
      const normalizedUrl = this.normalizeUrl(url)

      const containsAssets = normalizedUrl.includes('/assets/')
      const containsOssH5 = normalizedUrl.includes('/oss/h5/')
      const startsWithOss = normalizedUrl.startsWith(
        'https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5/'
      )

      // 只缓存三种类型的资源
      return containsAssets || containsOssH5 || startsWithOss
    } catch (error) {
      console.warn('判断资源类型时出错:', error)
      return false
    }
  }

  // 规范化 URL 以确保一致性
  normalizeUrl(url) {
    try {
      // 如果是相对路径，转换为完整 URL 进行匹配
      if (url.startsWith('/')) {
        return new URL(url, window.location.origin).toString()
      }
      // 如果已经是完整 URL，直接返回
      return new URL(url).toString()
    } catch (e) {
      // 如果 URL 格式不正确，返回原 URL
      return url
    }
  }

  // 缓存图片
  async cacheImage(url) {
    if (!('caches' in window) || !url) return

    try {
      if (this.isBuildAsset(url)) {
        const cache = await this.getCacheForUrl(url)
        const cachedResponse = await cache.match(url)

        if (!cachedResponse) {
          const response = await fetch(url, {
            mode: 'cors',
            credentials: 'omit',
            cache: 'no-store', // 强制不使用 HTTP 缓存
            headers: {
              'Cache-Control': 'no-cache, no-store, must-revalidate',
              Pragma: 'no-cache',
              Expires: '0',
            },
          })
          if (response.ok) {
            await cache.put(url, response.clone())
            // 添加新图片后立即检查并强制执行限制
            await this.enforceCacheLimits(cache)
          }
        }
      }
    } catch (error) {
      console.warn(`缓存图片失败 ${url}:`, error)
    }
  }

  // 获取缓存的图片 Blob URL（如果是缓存的图片会返回 blob URL，否则返回原始 URL）
  async getCacheImageUrl(url) {
    if (!('caches' in window)) return url

    try {
      // 规范化 URL
      const normalizedUrl = this.normalizeUrl(url)

      // 目标符合缓存条件
      if (this.isBuildAsset(normalizedUrl)) {
        const cache = await this.getCacheForUrl(normalizedUrl)

        // 尝试多种匹配方式以确保找到缓存的图片
        // 1. 首先尝试使用 Request 对象进行精确匹配
        const request = new Request(normalizedUrl, {
          mode: 'cors',
          credentials: 'omit',
        })
        let cachedResponse = await cache.match(request)

        // 2. 如果精确匹配失败，尝试直接使用 URL 字符串匹配
        if (!cachedResponse) {
          cachedResponse = await cache.match(normalizedUrl)
        }

        // 3. 如果还是没找到，尝试使用 URL 的 origin + pathname（去掉查询参数）
        if (!cachedResponse) {
          const urlObj = new URL(normalizedUrl)
          const urlWithoutQuery = `${urlObj.origin}${urlObj.pathname}`
          cachedResponse = await cache.match(urlWithoutQuery)
        }

        // 4. 尝试匹配去掉协议的 URL
        if (!cachedResponse) {
          const urlWithoutProtocol = normalizedUrl.replace(/^https?:\/\//, '')
          cachedResponse = await cache.match(urlWithoutProtocol)
        }

        // 经过上面流程后，匹配成功
        if (cachedResponse) {
          const blob = await cachedResponse.blob() // 获取命中缓存对象的blob
          return URL.createObjectURL(blob) // 返回创建的 Blob URL
        }
        // 经过上面流程后，缓存依旧未命中
        else {
          try {
            await this.cacheImage(normalizedUrl) // 触发预缓存
          } catch (cacheError) {
            console.warn(`预缓存失败: ${cacheError}`)
          }
        }
      }

      return url // 不符合缓存条件，直接返回原始 URL
    } catch (error) {
      console.warn('获取缓存图片 URL 失败:', error)
      return url
    }
  }

  // 从缓存获取图片
  async getCachedImage(url) {
    if (!('caches' in window)) return null

    try {
      // 规范化 URL
      const normalizedUrl = this.normalizeUrl(url)

      // 只从缓存获取本地资源
      if (this.isBuildAsset(normalizedUrl)) {
        const cache = await this.getCacheForUrl(normalizedUrl) // 选中对应缓存

        // 尝试多种匹配方式
        let cachedResponse = await cache.match(
          new Request(normalizedUrl, {
            mode: 'cors',
            credentials: 'omit',
          })
        )

        if (!cachedResponse) {
          cachedResponse = await cache.match(normalizedUrl)
        }

        if (!cachedResponse) {
          const urlObj = new URL(normalizedUrl)
          const urlWithoutQuery = `${urlObj.origin}${urlObj.pathname}`
          cachedResponse = await cache.match(urlWithoutQuery)
        }

        return cachedResponse
      }
      return null
    } catch (error) {
      console.warn('获取缓存图片失败:', error)
      return null
    }
  }

  // 智能加载图片
  async loadImage(src) {
    // 规范化 URL
    const normalizedSrc = this.normalizeUrl(src)

    // 1. 请求去重：检查是否有相同请求正在进行
    if (this.pendingRequests.has(normalizedSrc)) {
      return this.pendingRequests.get(normalizedSrc) // 返回对应的Promise，避免重复请求
    }

    // 2. 请求列表中不存在，则创建新的加载Promise
    const loadPromise = new Promise(async (resolve, reject) => {
      try {
        const cachedResponse = await this.getCachedImage(normalizedSrc) // 3. 获取对应的缓存图片
        // 4. 缓存命中，处理图片
        if (cachedResponse) {
          const blob = await cachedResponse.blob() //将缓存响应转换为 Blob 对象
          const imageUrl = URL.createObjectURL(blob) //生成临时的 Blob URL 供 Image 对象使用

          const img = new Image() // 5. 创建Image对象并设置src

          // 设置 onload 和 onerror 回调
          img.onload = () => {
            URL.revokeObjectURL(imageUrl) // 清理临时URL
            resolve(img)
          }

          img.onerror = () => {
            URL.revokeObjectURL(imageUrl) // 8. 清理临时URL
            this.loadImageFromNetwork(normalizedSrc, resolve, reject) // 9. 回退到网络加载
          }

          img.src = imageUrl // 10. 开始加载
          return
        }

        this.loadImageFromNetwork(normalizedSrc, resolve, reject) // 11. 缓存中没有或不是本地资源，从网络加载
      } catch (error) {
        this.loadImageFromNetwork(normalizedSrc, resolve, reject) // 12. 网络加载失败，回退到网络加载
      }
    })

    // 12. 记录正在进行的请求
    this.pendingRequests.set(normalizedSrc, loadPromise)

    try {
      const result = await loadPromise // 等待加载完成
      return result
    } finally {
      this.pendingRequests.delete(normalizedSrc) // 13. 清理记录
    }
  }

  // 从网络加载图片
  async loadImageFromNetwork(src, resolve, reject) {
    try {
      // 规范化 URL
      const normalizedSrc = this.normalizeUrl(src)

      // 统一处理所有资源，不再对OSS做特殊处理
      const response = await fetch(normalizedSrc, {
        mode: 'cors',
        credentials: 'omit',
        cache: 'no-store', // 强制不使用 HTTP 缓存
      })

      // 加载完成
      if (response.ok) {
        // 克隆响应，一份用于缓存，一份用于图片加载
        const isAsset = this.isBuildAsset(normalizedSrc) // 检查是否为适合缓存的资源
        const responseForCache = isAsset ? response.clone() : null //复制适合缓存的资源
        const responseForImage = response // 原始响应用于图片加载

        // 适合缓存
        if (isAsset) {
          try {
            const cache = await this.getCacheForUrl(normalizedSrc) // 获取对应的缓存
            await cache.put(normalizedSrc, responseForCache) // 缓存克隆的响应
          } catch (cacheError) {
            console.warn('缓存图片时出错:', cacheError)
          }
        }

        // 创建Image对象并设置src
        const img = new Image()
        img.onload = () => {
          resolve(img)
        }
        img.onerror = (error) => {
          reject(error)
        }
        img.src = URL.createObjectURL(await responseForImage.blob()) // 使用原始响应
      }
      // 加载失败
      else {
        reject(new Error(`HTTP ${response.status}`))
      }
    } catch (error) {
      reject(error)
    }
  }

  // 获取当前版本的缓存名称
  getCacheNameByUrl(url) {
    const normalizedUrl = this.normalizeUrl(url)

    if (
      normalizedUrl.startsWith('https://tkm-likei.oss-ap-southeast-1.aliyuncs.com/h5') ||
      normalizedUrl.includes('/oss/h5/')
    ) {
      return this.imageCacheName
    } else if (normalizedUrl.includes('/assets/')) {
      return this.assetCacheName
    } else {
      return this.imageCacheName
    }
  }
}

// 导出单例
export const imageCacheManager = new ImageCacheManager()
