import 'dart:async';
import 'dart:ui' show ImmutableBuffer, ImageDescriptor;

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:json_annotation/json_annotation.dart';

import 'index.dart';

part 'zoom_logic.g.dart';

class ZoomLogic extends GetxController {
  ZoomState zoomState = ZoomState(
    initScale: Rx<double?>(null),
    zoomFile: Rx<ZoomFileModel?>(null),
  );

  var oldTemplateId;
  StreamSubscription? _streamHomework;
  StreamSubscription? _streamZoomState;

  StreamSubscription<double?>? initScaleStream;

  Map<int, ZoomFileModel> imageSizeMap = {};

  HomeworkReviewLogic get homeworkReviewLogic => Get.find<HomeworkReviewLogic>();

  @override
  void onInit() {
    oldTemplateId = zoomState.zoomFile.value?.templateId;

    /// 根据第一次加载的试题题号 分析试题图片所占的宽高
    _streamZoomState = zoomState.zoomFile.listen((e) => refreshZoomFile(e));

    WidgetsBinding.instance.addPostFrameCallback((e) {
      /// 试题加载后更新尺寸对象（只要题号没有变就不更新尺寸对象）
      _streamHomework = homeworkReviewLogic.state.data.listen((e) {
        var zoomFile = zoomState.zoomFile.value;
        if (e == null || zoomFile == null) return;

        if (zoomFile.templateId != e.templateId) {
          // zoom 题号判断是否有变 有变就需要清空 zoom文件
          zoomState.initScale.value = null;
          zoomFile = ZoomFileModel(
            templateId: e.templateId,
            viewWidth: zoomFile.viewWidth,
            viewHeight: zoomFile.viewHeight,
          );

          /// 重置缩放和位置
          _resetZoom();
        }

        /// 更新尺寸对象
        refreshZoomFile(zoomFile);
      });
    });

    /// 监听缩放
    initScaleStream = zoomState.initScale.listen((e) {});

    super.onInit();
  }

  @override
  void onClose() {
    _streamHomework?.cancel();
    _streamZoomState?.cancel();
    super.onClose();
  }

  void refreshZoomFile(ZoomFileModel? e) {
    var templateId = e?.templateId;
    if (templateId == null) return;

    var homeworkData = homeworkReviewLogic.state.data.value;
    var zgtAnswer = homeworkData?.zgtAnswer;
    if (zgtAnswer == null || oldTemplateId == templateId) return;

    // getNetworkImageDimensions(zgtAnswer);

    oldTemplateId = templateId;
    final fileSize = imageSizeMap[templateId];
    // 移除冗余日志，避免频繁 I/O
    if (fileSize != null) {
      zoomState.zoomFile.value = fileSize;
      return;
    }

    /// 第三方库网络图，图片会被解码并缓存于内存
    CachedNetworkImageProvider(zgtAnswer).getImageSize().then((s) {
      if (s == null) return;

      // 提取宽度和高度
      var oldZoomFile = zoomState.zoomFile.value!;

      /// 重置部分数据 避免数据被覆盖
      var newZoomFile = ZoomFileModel(
        templateId: templateId,
        viewWidth: oldZoomFile.viewWidth,
        viewHeight: oldZoomFile.viewHeight,
        fileWidth: s.width,
        fileHeight: s.height,
      );

      /// 初始化zoom文件
      imageSizeMap[templateId] = newZoomFile;
      zoomState.zoomFile.value = newZoomFile;
    });
  }

  // 缩放组件 ==> 缩放监听
  void onScaleUpdate(double zoom) async {
    /// 防抖
    zoomState.initScale.value = zoom;
    // anti_shake_throttling.debounce(() => zoomState.initScale.value = zoom, const Duration(milliseconds: 100))();
  }

  // 缩放组件 ==> 位置更新
  void onPanUpPosition(Offset val) async {
    // 手指在移动 非物体移动的位置
    var state = homeworkReviewLogic.state;
    state.zoomOffset = val;
    state.slide.value = val.dy.abs().toInt().toDouble();
  }

  // 重置缩放和位置
  void _resetZoom() {
    // 重置缩放状态
    zoomState.initScale.value = 1.0;

    // 重置位置偏移
    homeworkReviewLogic.state.zoomOffset = Offset.zero;
    homeworkReviewLogic.state.slide.value = 0.0;
  }
}

class HomeworkReviewZoomBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => ZoomLogic());
  }
}

class ZoomState {
  final Rx<double?> initScale;
  final Rx<ZoomFileModel?> zoomFile;

  const ZoomState({required this.zoomFile, required this.initScale});
}

@JsonSerializable()
class ZoomFileModel extends Object {
  double viewWidth; // 容器宽度
  double viewHeight; // 容器高度

  double scaleRatio; // 基准

  int? templateId; // 页码

  double? pixelRatio; // 像素比率

  double? fileWidth; // 文件宽度
  double? fileHeight; // 文件高度

  double? actualWidth; // 实际展示宽度
  double? actualHeight; // 实际展示高度

  double? remainingHeight; // 视图剩余高度 实际展示图片展示高度下 剩余高度.(若为负数就是超出视图的高度值)
  double? imageHeightOffsetStart; // 顶部坐标Y
  double? imageHeightOffsetend; // 底部坐标Y

  ZoomFileModel({
    required this.viewWidth,
    required this.viewHeight,
    this.scaleRatio = 1,
    this.templateId,
    this.fileWidth,
    this.fileHeight,
    this.actualWidth,
    this.actualHeight,
    this.remainingHeight,
    this.imageHeightOffsetStart,
    this.imageHeightOffsetend,
    this.pixelRatio,
  }) {
    /// 初始化尺寸信息
    // 图片已视图宽为基准，高度自适应可滑动   图片的实际宽高都需要乘此基准值.
    if (fileHeight != null && fileWidth != null) {
      scaleRatio = viewWidth / fileWidth!;
      actualWidth = fileWidth! * scaleRatio;
      actualHeight = fileHeight! * scaleRatio;

      pixelRatio = fileWidth! / viewWidth; // 图片在此设备的像素比例

      remainingHeight = viewHeight - actualHeight!;
      imageHeightOffsetStart = remainingHeight! / 2;
      imageHeightOffsetend = imageHeightOffsetStart! + actualHeight!;
    }
  }

  factory ZoomFileModel.fromJson(Map<String, dynamic> srcJson) => _$ZoomFileModelFromJson(srcJson);

  Map<String, dynamic> toJson() => _$ZoomFileModelToJson(this);

  // 清空zoom文件（templateId 页码变换清空试题图片信息）
  ZoomFileModel clearZoomFile(int newTemplateId) {
    templateId = newTemplateId; // 页码
    fileWidth = null; // 文件宽度
    fileHeight = null; // 文件高度
    actualWidth = null; // 实际展示宽度
    actualHeight = null; // 实际展示高度
    remainingHeight = null; // 视图剩余高度 实际展示图片展示高度下 剩余高度.(若为负数就是超出视图的高度值)
    imageHeightOffsetStart = null; // 顶部坐标Y
    imageHeightOffsetend = null; // 底部坐标Y
    return this;
  }

  /// 获取缩放比例后的空白距离
  /// zoom 缩放比例
  double getZoomFileOffsetStart(double zoom) {
    if (zoom == 1 || actualHeight == null) return imageHeightOffsetStart ?? 0;
    return (viewHeight - (actualHeight! * zoom)) / 2;
  }

  /// 获取宽度的缩放后的空间距离
  /// zoom 缩放比例
  double getZoomFileOffsetStartWidth(double zoom) {
    if (zoom >= 1 || actualWidth == null) return 0;

    return (viewWidth - (actualWidth! * zoom)) / 2;
  }

  /// 获取缩放比例后的底部图片位置
  /// zoom 缩放比例
  double getZoomFileHeightOffsetEnd(double zoom) {
    if (zoom == 1 || actualHeight == null) return imageHeightOffsetend ?? 0;
    var topSpaceDimensions = getZoomFileOffsetStart(zoom);
    return topSpaceDimensions + (actualHeight! * zoom);
  }
}

// 最终版
extension GetImageSize on ImageProvider {
  Future<Size?> getImageSize({bool avoidDecode = false}) async {
    if (avoidDecode) {
      // 是否要免解码
      final cacheStatus = await obtainCacheStatus(configuration: const ImageConfiguration());
      final tracked = cacheStatus?.tracked ?? false;
      // 内存缓存中存在时优先从缓存中取，不在内存缓存中时转换为 ImageDescriptor
      if (!tracked) {
        ImmutableBuffer? buffer;
        if (this is AssetBundleImageProvider) {
          final key = await obtainKey(const ImageConfiguration()) as AssetBundleImageKey;
          buffer = await key.bundle.loadBuffer(key.name);
        } else if (this is FileImage) {
          final file = (this as FileImage).file;
          final int lengthInBytes = await file.length();
          if (lengthInBytes > 0) {
            buffer = await ImmutableBuffer.fromFilePath(file.path);
          }
        } else if (this is MemoryImage) {
          final bytes = (this as MemoryImage).bytes;
          buffer = await ImmutableBuffer.fromUint8List(bytes);
        }
        if (buffer != null) {
          final descriptor = await ImageDescriptor.encoded(buffer);
          final size = Size(descriptor.width.toDouble(), descriptor.height.toDouble());
          buffer.dispose();
          descriptor.dispose();
          if (!size.isEmpty) return size;
        }
      }
    }

    // 免解码末开启或内存缓存已存在，最后再兜底上面未处理的情况
    final completer = Completer<Size?>();
    ImageStream imageStream = resolve(const ImageConfiguration());

    ImageStreamListener? listener;
    listener = ImageStreamListener(
      (imageInfo, synchronousCall) {
        if (!completer.isCompleted) {
          completer.complete(Size(imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble()));
        }
        WidgetsBinding.instance.addPostFrameCallback((_) {
          imageInfo.dispose();
          imageStream.removeListener(listener!);
        });
      },
      onError: (exception, stackTrace) {
        if (!completer.isCompleted) {
          completer.complete();
        }
        imageStream.removeListener(listener!);
      },
    );
    imageStream.addListener(listener);

    return completer.future;
  }
}
