import 'dart:typed_data';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:crypto/crypto.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared/utils/log_utils.dart';
import 'dart:convert';
import 'package:path/path.dart' as path;
import 'package:synchronized/synchronized.dart';

import 'cache_item.dart';
import 'cache_item_adapter.dart';

enum CacheBoxType {
  httpCache,
  appCache,
  logCache,
  encryptedCache,
  // 可以根据需要添加更多类型
}

class LocalCacheManager {
  static final LocalCacheManager _instance = LocalCacheManager._internal();

  factory LocalCacheManager() {
    return _instance;
  }

  LocalCacheManager._internal();

  final Map<CacheBoxType, Box> _boxes = {};
  bool _isInitialized = false;
  late HiveCipher _cipher;

  Future<void> init({String? encryptionKey}) async {
    if (_isInitialized) return;

    await Hive.initFlutter('hive_boxes');

    Hive.registerAdapter(CacheItemAdapter<dynamic>()); //默认注册缓存的对象

    // 获取应用文档目录
    final appDocumentDir = await getApplicationDocumentsDirectory();
    final hiveBoxesPath = path.join(appDocumentDir.path, 'hive_boxes');

    _collection = await BoxCollection.open(
      _collectionName,
      {'app_cache', 'http_data', 'log', 'encrypt'},
      path: hiveBoxesPath,
    );

    if (encryptionKey != null) {
      final key = Uint8List.fromList(sha256.convert(utf8.encode(encryptionKey)).bytes);
      _cipher = HiveAesCipher(key);
    }

    _isInitialized = true;
    Log.d("LocalCacheManager 初始化完成");
  }

  Future<Box> _getBox(CacheBoxType boxType) async {
    if (!_isInitialized) {
      throw StateError('LocalCacheManager not initialized. Call init() first.');
    }

    if (!_boxes.containsKey(boxType)) {
      final box = await Hive.openBox(
        boxType.toString(),
        encryptionCipher: boxType == CacheBoxType.encryptedCache ? _cipher : null,
      );
      _boxes[boxType] = box;
    }
    return _boxes[boxType]!;
  }

  Future<void> put<T>(
    String key,
    T value, {
    CacheBoxType boxType = CacheBoxType.appCache,
    Duration? expiry,
  }) async {
    final box = await _getBox(boxType);
    final expiryTime = expiry != null ? DateTime.now().add(expiry).millisecondsSinceEpoch : null;
    final cacheItem = CacheItem<T>(value, expiryTime);
    await box.put(key, cacheItem);
  }

  Future<T?> get<T>(
    String key, {
    CacheBoxType boxType = CacheBoxType.appCache,
  }) async {
    final box = await _getBox(boxType);
    final cacheItem = box.get(key) as CacheItem<T>?;
    if (cacheItem == null) return null;
    if (cacheItem.isExpired) {
      await delete(key, boxType: boxType);
      return null;
    }
    return cacheItem.value;
  }

  Future<void> delete(String key, {CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    await box.delete(key);
  }

  Future<int> add(dynamic value, {CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    return box.add(value);
  }

  Future<List<dynamic>> getAllValues({CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    return box.values.toList();
  }

  Future<void> clear({CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    await box.clear();
  }

  Future<void> closeBox(CacheBoxType boxType) async {
    if (_boxes.containsKey(boxType)) {
      await _boxes[boxType]!.close();
      _boxes.remove(boxType);
    }
  }

  Future<void> closeAllBoxes() async {
    for (var boxType in _boxes.keys.toList()) {
      await closeBox(boxType);
    }
  }

  static const String _collectionName = 'my_app_collection';
  BoxCollection? _collection;
  final _initLock = Lock();

  // 改进的 _getCollection 方法
  Future<BoxCollection> _getCollection() async {
    if (_collection != null) {
      return _collection!;
    }

    return _initLock.synchronized(() async {
      if (_collection != null) {
        return _collection!;
      }

      _collection = await BoxCollection.open(
        _collectionName,
        {'app_cache', 'user_data', 'settings'},
        path: 'path/to/your/hive/boxes',
      );

      return _collection!;
    });
  }

  // 根据CacheBoxType获取对应的box名称
  String _getBoxName(CacheBoxType type) {
    switch (type) {
      case CacheBoxType.appCache:
        return 'app_cache';
      case CacheBoxType.httpCache:
        return 'http_data';
      case CacheBoxType.logCache:
        return 'log';
      case CacheBoxType.encryptedCache:
        return 'encrypt';
      default:
        throw ArgumentError('Unsupported CacheBoxType: $type');
    }
  }

  // 事务方法
  Future<void> performTransaction(
    Future<void> Function() transaction, {
    List<CacheBoxType> boxTypes = const [CacheBoxType.appCache],
    bool readOnly = false,
  }) async {
    final collection = await _getCollection();
    final boxNames = boxTypes.map((type) => _getBoxName(type)).toList();

    await collection.transaction(
      () async {
        await transaction();
      },
      boxNames: boxNames,
      readOnly: readOnly,
    );
  }

  // 批量操作方法
  Future<void> putAll(Map<String, dynamic> entries, {CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    await box.putAll(entries);
  }

  // 获取所有键
  Future<List<String>> getAllKeys({CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    return box.keys.cast<String>().toList();
  }

  // 检查键是否存在
  Future<bool> containsKey(String key, {CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    return box.containsKey(key);
  }

  // 获取缓存大小
  Future<int> getSize({CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    return box.length;
  }

  // 监听缓存变化
  void listenToChanges(void Function(BoxEvent) onChanged, {CacheBoxType boxType = CacheBoxType.appCache}) async {
    final box = await _getBox(boxType);
    box.watch().listen(onChanged);
  }

  //获取当前Key的有效事件
  Future<Duration?> getTimeToLive(
    String key, {
    CacheBoxType boxType = CacheBoxType.appCache,
  }) async {
    final box = await _getBox(boxType);
    final cacheItem = box.get(key) as CacheItem?;
    if (cacheItem == null || cacheItem.expiryTime == null) return null;
    final expiryTime = DateTime.fromMillisecondsSinceEpoch(cacheItem.expiryTime!);
    final now = DateTime.now();
    if (now.isAfter(expiryTime)) {
      await delete(key, boxType: boxType);
      return null;
    }
    return expiryTime.difference(now);
  }

  //更新当前Key的有效时间
  Future<void> updateExpiry(
    String key,
    Duration newExpiry, {
    CacheBoxType boxType = CacheBoxType.appCache,
  }) async {
    final box = await _getBox(boxType);
    final cacheItem = box.get(key) as CacheItem?;
    if (cacheItem == null) return;
    final newExpiryTime = DateTime.now().add(newExpiry).millisecondsSinceEpoch;
    final updatedCacheItem = CacheItem(cacheItem.value, newExpiryTime);
    await box.put(key, updatedCacheItem);
  }
}

//可以用 LocalCacheManager 直接使用更方便
var localCache = LocalCacheManager();
