/**
 * 类型安全的 localStorage 封装，具备严格的 key 管理
 */

// 1. 定义应用程序使用的存储键名（防止使用任意字符串作为 key）
export enum AppStorageKey {
  PASSPORT_DATA = 'passportData',
  PASSPORT_TOKEN = 'passportToken',
  MENU_DATA = 'menuData', // 全部的菜单数据
  SLIDER_MENU = 'sliderMenu', // 侧边栏菜单数据
  USER_INFO = 'userInfo',
  TOKEN = 'token',
  MODE = 'mode', // 日间夜间模式
}

// 2. 存储值类型定义（用于内部处理）
type StorageValue<T> = {
  __data: T // 实际存储的数据
  __expiry?: number // 可选的过期时间戳
}

// 3. 主存储类
class SafeStorage {
  /**
   * 存储数据（自动处理 JSON 序列化）
   * @param key 预定义的存储键
   * @param value 要存储的值（支持所有 JSON 安全类型）
   * @param ttl 可选的时间有效期（毫秒）
   */
  static set<T>(key: AppStorageKey, value: T, ttl?: number): void {
    if (typeof window === 'undefined') return

    try {
      // 创建存储对象（包含数据值和过期时间）
      const storageValue: StorageValue<T> = {
        __data: value,
      }

      // 设置过期时间（如果提供）
      if (ttl !== undefined && ttl > 0) {
        storageValue.__expiry = Date.now() + ttl
      }

      // 自动序列化并存储
      localStorage.setItem(key, JSON.stringify(storageValue))
    } catch (error) {
      console.error(`[存储] 保存失败 (key: ${key})`, error)
      this.handleStorageError(key, error)
    }
  }

  /**
   * 获取数据（自动反序列化并检查过期）
   * @param key 预定义的存储键
   * @returns 存储的值或 null（如果不存在或过期）
   */
  static get<T>(key: AppStorageKey): T | null {
    if (typeof window === 'undefined') return null

    try {
      // 获取原始数据
      const rawData = localStorage.getItem(key)
      if (!rawData) return null

      // 解析为内部存储结构
      const storageValue = JSON.parse(rawData) as StorageValue<T>

      // 检查是否过期
      if (this.isExpired(storageValue)) {
        this.remove(key)
        return null
      }

      // 返回实际数据
      return storageValue.__data
    } catch (error) {
      console.error(`[存储] 解析失败 (key: ${key})`, error)
      this.remove(key) // 移除无效数据
      return null
    }
  }

  /**
   * 删除指定存储项
   * @param key 要删除的存储键
   */
  static remove(key: AppStorageKey): void {
    if (typeof window === 'undefined') return
    localStorage.removeItem(key)
  }

  /**
   * 清除应用相关的所有存储
   */
  static clearAppStorage(): void {
    if (typeof window === 'undefined') return

    // 遍历所有预定义的 key 进行删除
    Object.values(AppStorageKey).forEach((key) => {
      localStorage.removeItem(key)
    })
  }

  // ----------------------------- 私有辅助方法 -----------------------------

  /**
   * 检查存储值是否过期
   */
  private static isExpired<T>(value: StorageValue<T>): boolean {
    return value.__expiry !== undefined && Date.now() > value.__expiry
  }

  /**
   * 处理存储错误（配额不足等）
   */
  private static handleStorageError(key: AppStorageKey, error: unknown): void {
    // 处理存储空间不足错误
    if (error instanceof DOMException && error.name === 'QuotaExceededError') {
      console.warn('存储空间不足，尝试清理过期数据')
      this.clearExpiredItems()

      // 尝试重新存储（最多尝试一次）
      try {
        const raw = localStorage.getItem(key)
        if (raw) {
          const value = JSON.parse(raw) as StorageValue<unknown>
          if (!this.isExpired(value)) {
            localStorage.setItem(key, raw)
            return
          }
        }
      } catch (retryError) {
        console.error('重试存储失败', retryError)
      }
    }
  }

  /**
   * 清理所有过期的存储项
   */
  private static clearExpiredItems(): void {
    Object.values(AppStorageKey).forEach((key) => {
      try {
        const raw = localStorage.getItem(key)
        if (raw) {
          const value = JSON.parse(raw) as StorageValue<unknown>
          if (this.isExpired(value)) {
            localStorage.removeItem(key)
          }
        }
      } catch (e) {
        // 忽略无效数据
      }
    })
  }
}

export default SafeStorage
