import 'dart:async';
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:logging/logging.dart';
import 'package:puzzleweave/models/api_helper.dart';
import 'package:puzzleweave/models/data.dart';
import 'package:puzzleweave/models/items.dart';
import 'package:puzzleweave/utils/utils.dart';

final Logger _log = Logger('download.dart');

/// 最多缓存/并发下载n个图到内存
const maxCachedItems = 1;

/// Singleton
class Download {
  static final Download _instance = Download._internal();

  factory Download() => _instance;
  Download._internal();

  final Map<String, DownloadItem> _cache = {};

  DownloadItem download(String url, String cachePath) {
    if (_cache[url] != null) {
      _log.info('Cache hit for $url');
      _cache[url]!.touch();
      return _cache[url]!;
    } else {
      final item = DownloadItem(url, cachePath);
      _cache[url] = item;
      _watch(item);
      return item;
    }
  }

  _watch(DownloadItem item) async {
    try {
      await item.loadCompleter.future;
      // !!! 修正点 1: 在任务完成后，异步触发清理
      // 任务完成后，它占用的内存 Image 和 Data 就可以被清理了
      Future.microtask(_clean);
    } catch (err) {
      // 发生错误，立即移除缓存项
      _log.info('Watch download item got error: $err');
      _cache.remove(item.url);
    }
  }

  _clean() {
    final list = _cache.values.where((item) => item.loadCompleter.isCompleted).toList();
    if (list.length <= maxCachedItems) return;
    _log.info('cleaning...');

    // 2. 按最近使用时间排序（时间越早越应该被清理）
    list.sort((a, b) => a.lastUsed.compareTo(b.lastUsed));
    // 3. 清理到只剩下 maxCachedItems 个
    while (list.length > maxCachedItems) {
      final item = list.removeAt(0);
      _log.info('Cleaning item from memory: $item');
      item.dispose();
      _cache.remove(item.url);
    }
  }

  clearAllCached() async {
    final file = await localFile('cache');
    await file.delete(recursive: true);
  }
}

class DownloadItem {
  final String url;
  final String cachePath;
  ValueNotifier<double> progress = ValueNotifier(0.0);
  final Completer<void> loadCompleter = Completer(); // 仅作为完成信号
  Client? client;
  StreamSubscription? subscription;
  int lastUsed;
  Uint8List? _data;

  DownloadItem(this.url, this.cachePath) : lastUsed = DateTime.now().millisecondsSinceEpoch {
    _log.info('New download item for: $url');
    _start();
  }

  Uint8List? get data => _data;
  set data(Uint8List? val) => _data = val;

  touch() => lastUsed = DateTime.now().millisecondsSinceEpoch;

  _start() async {
    try {
      await _download();
      if (!loadCompleter.isCompleted) loadCompleter.complete();
    } catch (err) {
      if (!loadCompleter.isCompleted) loadCompleter.completeError(err);
    }
  }

  Future<void> _download() async {
    progress.value = 0;
    final file = await localFile(cachePath);
    _checkDispose();

    // 核心改造：如果文件存在，只报完成，不读数据 (Lazy Load)
    if (await file.exists()) {
      _log.info('Disk cache hit (Metadata only) for $cachePath');
      progress.value = 1.0;
      return;
    }

    // 网络下载逻辑
    final List<int> bytes = [];
    client = Client();
    final response = await client!.send(Request('GET', Uri.parse(url)));
    _checkDispose();

    if (response.statusCode != 200) throw Exception('Status:${response.statusCode}');
    final length = response.contentLength ?? 0;

    final streamCompleter = Completer();
    subscription = response.stream.listen(
      (value) {
        bytes.addAll(value);
        if (length > 0) progress.value = bytes.length / length;
      },
      onDone: () => streamCompleter.complete(),
      onError: (e) => streamCompleter.completeError(e),
      cancelOnError: true,
    );

    await streamCompleter.future;
    _checkDispose();

    // 剔除 24 字节干扰码
    if (bytes.length > 24) {
      bytes.removeRange(0, 24);
    }

    _data = Uint8List.fromList(bytes);
    await saveBytes(cachePath, _data!); // 写入磁盘
    _log.info('Download and save complete for $url');

    client?.close();
  }

  /// 供 Loader 真正需要数据时调用
  Future<Uint8List> ensureDataLoaded() async {
    if (_data != null) return _data!;
    _log.info('Performing late read from disk: $cachePath');
    final file = await localFile(cachePath);
    _data = await file.readAsBytes();
    return _data!;
  }

  bool _isDisposed = false;
  _checkDispose() {
    if (_isDisposed) throw Exception('Disposed');
  }

  dispose() {
    _isDisposed = true;
    _data = null; // 释放内存
    subscription?.cancel();
    client?.close();
  }

  @override
  String toString() => '[$cachePath]';
}

abstract class ItemLoader {
  final Completer completer = Completer();
  Uint8List? get data;
  ValueNotifier<double> get progress;

  ItemLoader();

  // 辅助方法：确保数据就绪后再解码
  Future<Uint8List> _prepareData() async {
    await completer.future;
    if (data == null) throw 'Data missing after completion';
    return data!;
  }

  Future<ui.Image> getImageBySize(int width, int height, {allowUpscaling = true}) async {
    final bytes = await _prepareData();
    final codec = await ui.instantiateImageCodec(bytes, targetHeight: height, targetWidth: width, allowUpscaling: allowUpscaling);
    return (await codec.getNextFrame()).image;
  }

  Future<ui.Image> getImage() async {
    final bytes = await _prepareData();
    final codec = await ui.instantiateImageCodec(bytes);
    return (await codec.getNextFrame()).image;
  }

  /// 专门用于预加载的静态方法，不创建 Loader 实例
  static void preload(ListItem item, String quality) {
    if (BuiltinRegistry.contains(item.id)) {
      _log.info('Preload: Skipping builtin ${item.id}');
      return;
    }
    if (item is RemoteItem) {
      // 触发 Download 但不等待读入内存
      Download().download(ApiHelper.imageUri(item.id, quality), item.cachePath);
    }
  }

  factory ItemLoader.load(ListItem item, String quality) {
    if (BuiltinRegistry.contains(item.id)) {
      _log.info('Built-in hit: ${item.id}, skip network.');
      return AssetItemLoader('assets/builtin/${item.id}.jpeg');
    }
    switch (item.runtimeType) {
      case RemoteItem:
        return RemoteItemLoader(ApiHelper.imageUri(item.id, quality), item.cachePath);
      case AssetItem:
        return AssetItemLoader((item as AssetItem).image);
      default:
        throw 'Unknown item type';
    }
  }
}

class AssetItemLoader extends ItemLoader {
  final String path;
  Uint8List? _data;

  @override
  ValueNotifier<double> progress = ValueNotifier(0);

  AssetItemLoader(this.path) {
    _load();
  }

  _load() async {
    try {
      _data = await loadFileDataFromAsset(path);
      completer.complete();
      progress.value = 1.0;
    } catch (e) {
      completer.completeError(e);
    }
  }

  @override
  Uint8List? get data => _data;
}

class RemoteItemLoader extends ItemLoader {
  final String url;
  final String cachePath;
  late final DownloadItem downloadItem;

  RemoteItemLoader(this.url, this.cachePath) {
    downloadItem = Download().download(url, cachePath);
    _load();
  }

  _load() async {
    try {
      await downloadItem.loadCompleter.future;
      // 在这里不读 data，getImage 时才读
      completer.complete();
    } catch (err) {
      completer.completeError(err);
    }
  }

  @override
  Uint8List? get data {
    // 同步获取（如果已读入内存），如果没读，需通过 getImage 异步触发
    return downloadItem.data;
  }

  @override
  Future<Uint8List> _prepareData() async {
    await completer.future;
    // 关键点：如果内存里没数据（预加载命中的缓存），在此处执行补读
    return await downloadItem.ensureDataLoaded();
  }

  @override
  ValueNotifier<double> get progress => downloadItem.progress;
}
