/**
 * 媒体缓存管理器
 * @module src/infrastructure/cache/MediaCacheManager
 * @description 管理图片、视频、音频缓存，支持多种清理策略
 */

import { File, Paths } from 'expo-file-system';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
  MediaType,
  CleanupTrigger,
  CacheEntry,
  CacheStats,
  CleanupPolicy,
  CleanupResult,
  MediaCacheConfig,
  DEFAULT_MEDIA_CACHE_CONFIG,
  DEFAULT_CLEANUP_POLICY,
} from './types';

/**
 * 缓存记录存储键前缀
 */
const CACHE_RECORD_PREFIX = 'media_cache_record_';

/**
 * 获取缓存目录路径
 */
function getCacheDir(): string {
  const cachePath = Paths.cache;
  return `${cachePath}media_cache/`;
}

/**
 * 获取图片缓存目录
 */
function getImageDir(): string {
  return `${getCacheDir()}images/`;
}

/**
 * 获取视频缓存目录
 */
function getVideoDir(): string {
  return `${getCacheDir()}videos/`;
}

/**
 * 获取音频缓存目录
 */
function getAudioDir(): string {
  return `${getCacheDir()}audios/`;
}

/**
 * 媒体缓存管理器类
 * @class MediaCacheManager
 * @description 单例模式，管理所有媒体文件的缓存
 */
export class MediaCacheManager {
  private static instance: MediaCacheManager;
  
  private cache: Map<string, CacheEntry> = new Map();
  private config: MediaCacheConfig;
  private policy: CleanupPolicy;
  private cleanupTimer: ReturnType<typeof setTimeout> | null = null;
  private lastCleanupTime: number = 0;
  private isInitialized: boolean = false;

  /**
   * 获取单例实例
   */
  public static getInstance(): MediaCacheManager {
    if (!MediaCacheManager.instance) {
      MediaCacheManager.instance = new MediaCacheManager();
    }
    return MediaCacheManager.instance;
  }

  /**
   * 私有构造函数
   */
  private constructor(
    config?: Partial<MediaCacheConfig>,
    policy?: Partial<CleanupPolicy>
  ) {
    this.config = { ...DEFAULT_MEDIA_CACHE_CONFIG, ...config };
    this.policy = { ...DEFAULT_CLEANUP_POLICY, ...policy };
  }

  /**
   * 初始化缓存管理器
   * 确保缓存目录存在并加载缓存记录
   */
  public async initialize(): Promise<void> {
    if (this.isInitialized) return;

    try {
      // 确保缓存目录存在
      await this.ensureDirectories();
      
      // 加载缓存记录
      await this.loadCacheRecords();
      
      // 启动时清理
      if (this.policy.cleanupOnStart) {
        await this.cleanup(CleanupTrigger.STARTUP);
      }
      
      // 启动定期清理
      this.startPeriodicCleanup();
      
      this.isInitialized = true;
    } catch (error) {
      console.error('[MediaCacheManager] 初始化失败:', error);
      throw error;
    }
  }

  /**
   * 确保缓存目录存在
   */
  private async ensureDirectories(): Promise<void> {
    try {
      const dirs = [getImageDir(), getVideoDir(), getAudioDir()];
      for (const dir of dirs) {
        const dirFile = new File(dir);
        if (!await dirFile.exists) {
          await dirFile.create();
        }
      }
    } catch (error) {
      console.error('[MediaCacheManager] 创建缓存目录失败:', error);
    }
  }

  /**
   * 从持久化存储加载缓存记录
   */
  private async loadCacheRecords(): Promise<void> {
    try {
      const keys = await AsyncStorage.getAllKeys();
      const recordKeys = keys.filter(k => k.startsWith(CACHE_RECORD_PREFIX));
      
      if (recordKeys.length === 0) return;

      const records = await AsyncStorage.multiGet(recordKeys);
      
      for (const [key, value] of records) {
        if (value) {
          const entry: CacheEntry = JSON.parse(value);
          // 验证文件是否存在
          const exists = await this.checkFileExists(entry.localPath);
          if (exists) {
            this.cache.set(entry.key, entry);
          } else {
            // 文件不存在，删除记录
            await AsyncStorage.removeItem(key);
          }
        }
      }
    } catch (error) {
      console.error('[MediaCacheManager] 加载缓存记录失败:', error);
    }
  }

  /**
   * 检查文件是否存在
   */
  private async checkFileExists(path: string): Promise<boolean> {
    try {
      const file = new File(path);
      return await file.exists;
    } catch {
      return false;
    }
  }

  /**
   * 记录缓存访问（用于LRU）
   */
  public async recordAccess(key: string): Promise<void> {
    const entry = this.cache.get(key);
    if (entry) {
      entry.lastAccessedAt = Date.now();
      await this.saveCacheRecord(entry);
    }
  }

  /**
   * 缓存媒体文件
   */
  public async cacheMedia(
    uri: string,
    type: MediaType,
    options: {
      conversationId?: string;
      messageId?: string;
      size?: number;
    } = {}
  ): Promise<string> {
    const { conversationId, messageId, size = 0 } = options;
    
    // 生成唯一键
    const key = this.generateCacheKey(uri, type);
    const localPath = this.getMediaPath(type, key);
    
    // 检查是否已缓存
    const existingEntry = this.cache.get(key);
    if (existingEntry) {
      await this.recordAccess(key);
      return existingEntry.localPath;
    }

    try {
      // 下载文件
      const destination = new File(localPath);
      const downloaded = await File.downloadFileAsync(uri, destination);
      
      // 获取实际文件大小
      let fileSize = size;
      // fileSize 为 0 时使用默认大小，实际应用中可以通过其他方式获取

      // 创建缓存条目
      const entry: CacheEntry = {
        key,
        type,
        uri,
        localPath: downloaded.uri,
        size: fileSize,
        conversationId,
        messageId,
        createdAt: Date.now(),
        lastAccessedAt: Date.now(),
      };

      // 保存记录
      this.cache.set(key, entry);
      await this.saveCacheRecord(entry);

      // 检查是否需要清理
      await this.checkAndCleanup();

      return downloaded.uri;
    } catch (error) {
      console.error('[MediaCacheManager] 缓存媒体失败:', error);
      throw error;
    }
  }

  /**
   * 获取缓存的媒体路径
   */
  public async getCachedMedia(uri: string, type: MediaType): Promise<string | null> {
    const key = this.generateCacheKey(uri, type);
    const entry = this.cache.get(key);
    
    if (entry) {
      const exists = await this.checkFileExists(entry.localPath);
      if (exists) {
        await this.recordAccess(key);
        return entry.localPath;
      } else {
        // 文件不存在，删除记录
        this.cache.delete(key);
        await this.removeCacheRecord(key);
      }
    }
    
    return null;
  }

  /**
   * 获取缓存统计信息
   */
  public getCacheStats(): CacheStats {
    const stats: CacheStats = {
      totalSize: 0,
      imageCount: 0,
      videoCount: 0,
      audioCount: 0,
      totalEntries: this.cache.size,
      oldestItem: Date.now(),
      newestItem: 0,
    };

    for (const entry of this.cache.values()) {
      stats.totalSize += entry.size;
      stats.oldestItem = Math.min(stats.oldestItem, entry.createdAt);
      stats.newestItem = Math.max(stats.newestItem, entry.createdAt);

      switch (entry.type) {
        case MediaType.IMAGE:
          stats.imageCount++;
          break;
        case MediaType.VIDEO:
          stats.videoCount++;
          break;
        case MediaType.AUDIO:
          stats.audioCount++;
          break;
      }
    }

    return stats;
  }

  /**
   * 清理操作入口
   */
  public async cleanup(trigger: CleanupTrigger): Promise<CleanupResult> {
    const errors: string[] = [];
    let deletedCount = 0;
    let freedSize = 0;
    const deletedItems: string[] = [];

    try {
      // 1. 清理过期缓存
      const expiredResult = await this.cleanupExpired();
      deletedCount += expiredResult.deletedCount;
      freedSize += expiredResult.freedSize;
      deletedItems.push(...expiredResult.deletedItems || []);
      errors.push(...expiredResult.errors);

      // 2. LRU清理（如果启用）
      if (this.policy.enableLRU) {
        const lruResult = await this.cleanupLRU();
        deletedCount += lruResult.deletedCount;
        freedSize += lruResult.freedSize;
        deletedItems.push(...lruResult.deletedItems || []);
        errors.push(...lruResult.errors);
      }

      // 3. 阈值清理
      const thresholdResult = await this.cleanupByThreshold();
      deletedCount += thresholdResult.deletedCount;
      freedSize += thresholdResult.freedSize;
      deletedItems.push(...thresholdResult.deletedItems || []);
      errors.push(...thresholdResult.errors);

      this.lastCleanupTime = Date.now();
    } catch (error) {
      errors.push(`清理失败: ${error instanceof Error ? error.message : '未知错误'}`);
    }

    return {
      trigger,
      timestamp: Date.now(),
      deletedCount,
      freedSize,
      errors,
      deletedItems,
    };
  }

  /**
   * 清理过期缓存
   */
  public async cleanupExpired(): Promise<CleanupResult> {
    const now = Date.now();
    const maxAge = this.policy.maxAge;
    const errors: string[] = [];
    let deletedCount = 0;
    let freedSize = 0;
    const deletedItems: string[] = [];

    const entriesToDelete: string[] = [];

    for (const [key, entry] of this.cache.entries()) {
      if (now - entry.lastAccessedAt > maxAge) {
        entriesToDelete.push(key);
      }
    }

    for (const key of entriesToDelete) {
      try {
        const entry = this.cache.get(key);
        if (entry) {
          const file = new File(entry.localPath);
          if (await file.exists) {
            await file.delete();
          }
          this.cache.delete(key);
          await this.removeCacheRecord(key);
          
          deletedCount++;
          freedSize += entry.size;
          deletedItems.push(key);
        }
      } catch (error) {
        errors.push(`删除 ${key} 失败: ${error instanceof Error ? error.message : '未知错误'}`);
      }
    }

    return {
      trigger: CleanupTrigger.MANUAL,
      timestamp: Date.now(),
      deletedCount,
      freedSize,
      errors,
      deletedItems,
    };
  }

  /**
   * LRU清理 - 删除最近最少使用的缓存
   */
  public async cleanupLRU(targetSize?: number): Promise<CleanupResult> {
    const errors: string[] = [];
    let deletedCount = 0;
    let freedSize = 0;
    const deletedItems: string[] = [];

    // 如果没有指定目标大小，使用最大缓存大小的一半
    const target = targetSize || Math.floor(this.policy.maxSize / 2);
    const currentStats = this.getCacheStats();
    
    if (currentStats.totalSize <= target) {
      return {
        trigger: CleanupTrigger.MANUAL,
        timestamp: Date.now(),
        deletedCount: 0,
        freedSize: 0,
        errors: [],
        deletedItems: [],
      };
    }

    // 按最后访问时间排序
    const sortedEntries = Array.from(this.cache.entries())
      .sort((a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt);

    let currentSize = currentStats.totalSize;

    for (const [key, entry] of sortedEntries) {
      if (currentSize <= target) break;

      try {
        const file = new File(entry.localPath);
        if (await file.exists) {
          await file.delete();
        }
        this.cache.delete(key);
        await this.removeCacheRecord(key);
        
        deletedCount++;
        freedSize += entry.size;
        deletedItems.push(key);
        currentSize -= entry.size;
      } catch (error) {
        errors.push(`删除 ${key} 失败: ${error instanceof Error ? error.message : '未知错误'}`);
      }
    }

    return {
      trigger: CleanupTrigger.MANUAL,
      timestamp: Date.now(),
      deletedCount,
      freedSize,
      errors,
      deletedItems,
    };
  }

  /**
   * 按阈值清理 - 超过最大大小时清理
   */
  private async cleanupByThreshold(): Promise<CleanupResult> {
    const currentStats = this.getCacheStats();
    const errors: string[] = [];
    let deletedCount = 0;
    let freedSize = 0;
    const deletedItems: string[] = [];

    // 检查总大小是否超过限制
    if (currentStats.totalSize <= this.policy.maxSize) {
      // 检查条目数是否超过限制
      if (currentStats.totalEntries <= this.policy.maxEntries) {
        return {
          trigger: CleanupTrigger.MANUAL,
          timestamp: Date.now(),
          deletedCount: 0,
          freedSize: 0,
          errors: [],
          deletedItems: [],
        };
      }
    }

    // 需要清理
    const targetSize = Math.floor(this.policy.maxSize * 0.8); // 清理到80%
    const targetEntries = Math.floor(this.policy.maxEntries * 0.8);

    // 按LRU排序
    const sortedEntries = Array.from(this.cache.entries())
      .sort((a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt);

    let currentSize = currentStats.totalSize;
    let currentEntries = currentStats.totalEntries;

    for (const [key, entry] of sortedEntries) {
      // 两个条件：大小或条目数
      if (currentSize <= targetSize && currentEntries <= targetEntries) break;

      try {
        const file = new File(entry.localPath);
        if (await file.exists) {
          await file.delete();
        }
        this.cache.delete(key);
        await this.removeCacheRecord(key);
        
        deletedCount++;
        freedSize += entry.size;
        deletedItems.push(key);
        currentSize -= entry.size;
        currentEntries--;
      } catch (error) {
        errors.push(`删除 ${key} 失败: ${error instanceof Error ? error.message : '未知错误'}`);
      }
    }

    return {
      trigger: CleanupTrigger.MANUAL,
      timestamp: Date.now(),
      deletedCount,
      freedSize,
      errors,
      deletedItems,
    };
  }

  /**
   * 删除指定会话的所有媒体缓存
   */
  public async clearConversationMedia(conversationId: string): Promise<CleanupResult> {
    const errors: string[] = [];
    let deletedCount = 0;
    let freedSize = 0;
    const deletedItems: string[] = [];

    const entriesToDelete: string[] = [];

    for (const [key, entry] of this.cache.entries()) {
      if (entry.conversationId === conversationId) {
        entriesToDelete.push(key);
      }
    }

    for (const key of entriesToDelete) {
      try {
        const entry = this.cache.get(key);
        if (entry) {
          const file = new File(entry.localPath);
          if (await file.exists) {
            await file.delete();
          }
          this.cache.delete(key);
          await this.removeCacheRecord(key);
          
          deletedCount++;
          freedSize += entry.size;
          deletedItems.push(key);
        }
      } catch (error) {
        errors.push(`删除 ${key} 失败: ${error instanceof Error ? error.message : '未知错误'}`);
      }
    }

    return {
      trigger: CleanupTrigger.CONVERSATION_DELETED,
      timestamp: Date.now(),
      deletedCount,
      freedSize,
      errors,
      deletedItems,
    };
  }

  /**
   * 清空所有缓存
   */
  public async clearAll(): Promise<void> {
    for (const entry of this.cache.values()) {
      try {
        const file = new File(entry.localPath);
        if (await file.exists) {
          await file.delete();
        }
      } catch (error) {
        console.warn(`[MediaCacheManager] 删除文件失败: ${entry.localPath}`, error);
      }
    }

    this.cache.clear();

    // 清除所有记录
    const keys = await AsyncStorage.getAllKeys();
    const recordKeys = keys.filter(k => k.startsWith(CACHE_RECORD_PREFIX));
    if (recordKeys.length > 0) {
      await AsyncStorage.multiRemove(recordKeys);
    }
  }

  /**
   * 启动定期清理
   */
  public startPeriodicCleanup(): void {
    if (this.cleanupTimer) {
      clearInterval(this.cleanupTimer);
    }

    this.cleanupTimer = setInterval(async () => {
      // 检查是否需要清理
      if (Date.now() - this.lastCleanupTime >= this.policy.cleanupInterval) {
        await this.cleanup(CleanupTrigger.SCHEDULED);
      }
    }, this.policy.cleanupInterval);
  }

  /**
   * 停止定期清理
   */
  public stopPeriodicCleanup(): void {
    if (this.cleanupTimer) {
      clearInterval(this.cleanupTimer);
      this.cleanupTimer = null;
    }
  }

  /**
   * 检查是否需要清理
   */
  private async checkAndCleanup(): Promise<void> {
    const stats = this.getCacheStats();
    
    // 检查大小
    if (stats.totalSize > this.policy.maxSize) {
      await this.cleanupLRU();
    }
    
    // 检查条目数
    if (stats.totalEntries > this.policy.maxEntries) {
      await this.cleanupLRU();
    }
  }

  /**
   * 保存缓存记录到持久化存储
   */
  private async saveCacheRecord(entry: CacheEntry): Promise<void> {
    try {
      const key = `${CACHE_RECORD_PREFIX}${entry.key}`;
      await AsyncStorage.setItem(key, JSON.stringify(entry));
    } catch (error) {
      console.error('[MediaCacheManager] 保存缓存记录失败:', error);
    }
  }

  /**
   * 删除缓存记录
   */
  private async removeCacheRecord(key: string): Promise<void> {
    try {
      const storageKey = `${CACHE_RECORD_PREFIX}${key}`;
      await AsyncStorage.removeItem(storageKey);
    } catch (error) {
      console.error('[MediaCacheManager] 删除缓存记录失败:', error);
    }
  }

  /**
   * 生成缓存键
   */
  private generateCacheKey(uri: string, type: MediaType): string {
    const hash = this.hashString(uri);
    return `${type.toLowerCase()}_${hash}_${Date.now()}`;
  }

  /**
   * 获取媒体文件存储路径
   */
  private getMediaPath(type: MediaType, key: string): string {
    const ext = this.getExtension(key, type);
    switch (type) {
      case MediaType.IMAGE:
        return `${getImageDir()}${key}.${ext}`;
      case MediaType.VIDEO:
        return `${getVideoDir()}${key}.${ext}`;
      case MediaType.AUDIO:
        return `${getAudioDir()}${key}.${ext}`;
    }
  }

  /**
   * 根据类型获取文件扩展名
   */
  private getExtension(key: string, type: MediaType): string {
    if (type === MediaType.IMAGE) {
      if (key.includes('gif')) return 'gif';
      if (key.includes('webp')) return 'webp';
      return 'jpg';
    }
    if (type === MediaType.VIDEO) return 'mp4';
    if (type === MediaType.AUDIO) return 'mp3';
    return 'bin';
  }

  /**
   * 字符串哈希函数
   */
  private hashString(str: string): string {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash;
    }
    return Math.abs(hash).toString(16);
  }
}

/**
 * 导出单例实例
 */
export const mediaCacheManager = MediaCacheManager.getInstance();
