/**
 * 磁盘缓存实现
 * 使用 JSON 文件存储，支持按文件路径索引
 */

import * as fs from 'fs/promises';
import * as path from 'path';
import { createHash } from 'crypto';

export interface CacheEntry<T> {
  key: string;
  value: T;
  timestamp: number;
}

/**
 * 磁盘缓存类
 */
export class DiskCache<T> {
  private cacheDir: string;
  private memoryCache: Map<string, T> = new Map();
  private dirty: Set<string> = new Set();
  private initialized = false;

  constructor(cacheDir: string) {
    this.cacheDir = cacheDir;
  }

  /**
   * 初始化缓存目录
   */
  private async ensureDir(): Promise<void> {
    if (this.initialized) return;

    try {
      await fs.mkdir(this.cacheDir, { recursive: true });
      this.initialized = true;
    } catch (error) {
      console.warn(`Failed to create cache directory: ${this.cacheDir}`, error);
    }
  }

  /**
   * 生成缓存文件路径
   */
  private getCacheFilePath(key: string): string {
    // 使用哈希避免文件名过长或包含特殊字符
    const hash = createHash('md5').update(key).digest('hex');
    return path.join(this.cacheDir, `${hash}.json`);
  }

  /**
   * 获取缓存值
   */
  async get(key: string): Promise<T | null> {
    // 先检查内存缓存
    if (this.memoryCache.has(key)) {
      return this.memoryCache.get(key)!;
    }

    await this.ensureDir();

    // 从磁盘读取
    const filePath = this.getCacheFilePath(key);
    try {
      const content = await fs.readFile(filePath, 'utf-8');
      const entry: CacheEntry<T> = JSON.parse(content);

      // 验证 key 匹配
      if (entry.key === key) {
        this.memoryCache.set(key, entry.value);
        return entry.value;
      }
    } catch {
      // 文件不存在或解析失败
    }

    return null;
  }

  /**
   * 设置缓存值
   */
  async set(key: string, value: T): Promise<void> {
    this.memoryCache.set(key, value);
    this.dirty.add(key);

    // 立即写入磁盘（可以优化为批量写入）
    await this.flush(key);
  }

  /**
   * 删除缓存
   */
  async delete(key: string): Promise<void> {
    this.memoryCache.delete(key);
    this.dirty.delete(key);

    await this.ensureDir();

    const filePath = this.getCacheFilePath(key);
    try {
      await fs.unlink(filePath);
    } catch {
      // 文件不存在
    }
  }

  /**
   * 检查缓存是否存在
   */
  async has(key: string): Promise<boolean> {
    if (this.memoryCache.has(key)) {
      return true;
    }

    const value = await this.get(key);
    return value !== null;
  }

  /**
   * 刷新指定 key 到磁盘
   */
  private async flush(key: string): Promise<void> {
    if (!this.dirty.has(key)) return;

    await this.ensureDir();

    const value = this.memoryCache.get(key);
    if (value === undefined) return;

    const entry: CacheEntry<T> = {
      key,
      value,
      timestamp: Date.now(),
    };

    const filePath = this.getCacheFilePath(key);
    try {
      await fs.writeFile(filePath, JSON.stringify(entry), 'utf-8');
      this.dirty.delete(key);
    } catch (error) {
      console.warn(`Failed to write cache: ${key}`, error);
    }
  }

  /**
   * 刷新所有脏数据到磁盘
   */
  async flushAll(): Promise<void> {
    const keys = Array.from(this.dirty);
    await Promise.all(keys.map((key) => this.flush(key)));
  }

  /**
   * 清空所有缓存
   */
  async clear(): Promise<void> {
    this.memoryCache.clear();
    this.dirty.clear();

    try {
      const files = await fs.readdir(this.cacheDir);
      await Promise.all(
        files
          .filter((f) => f.endsWith('.json'))
          .map((f) => fs.unlink(path.join(this.cacheDir, f)))
      );
    } catch {
      // 目录不存在或其他错误
    }
  }

  /**
   * 获取缓存大小（条目数）
   */
  size(): number {
    return this.memoryCache.size;
  }

  /**
   * 获取所有缓存的 keys
   */
  async keys(): Promise<string[]> {
    await this.ensureDir();

    const result: string[] = Array.from(this.memoryCache.keys());

    try {
      const files = await fs.readdir(this.cacheDir);
      for (const file of files) {
        if (!file.endsWith('.json')) continue;

        const filePath = path.join(this.cacheDir, file);
        try {
          const content = await fs.readFile(filePath, 'utf-8');
          const entry: CacheEntry<T> = JSON.parse(content);
          if (!result.includes(entry.key)) {
            result.push(entry.key);
          }
        } catch {
          // 跳过无效文件
        }
      }
    } catch {
      // 目录不存在
    }

    return result;
  }
}

/**
 * 创建磁盘缓存实例
 */
export function createDiskCache<T>(cacheDir: string): DiskCache<T> {
  return new DiskCache<T>(cacheDir);
}
