import 'dart:async';

import 'package:json_annotation/json_annotation.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:marking_app/common/mixin/common.dart';
import 'package:marking_app/common/model/job/job_handwriting.dart';
import 'package:marking_app/common/model/job/test_questions_image_info.dart';
import 'package:marking_app/pages/common/event_bus_mixin.dart';
import 'package:marking_app/pages/homework_correction/hooks/use_cached_img_refresh.dart';
import 'package:marking_app/utils/index.dart';
import 'package:marking_app/utils/my_text.dart';
import 'package:marking_app/utils/my_time_util.dart';

import '../../../common/model/job/gesture_recording.dart';
import '../providers/handwriting_drawing_trajectory_provider.dart';

part 'answer_handwriting.g.dart';

/// 学生答题轨迹
class AnswerHandwriting extends Dialog {
  final int jobId;
  final int studentId;
  final int? pageNum;
  final int? questionNo;
  final Function closeCall;
  const AnswerHandwriting({required this.jobId, required this.studentId, required this.closeCall, this.pageNum, this.questionNo});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: ScreenUtil().screenWidth - (ScreenUtil().scaleHeight < 1.5 ? 100.r : 60.r),
        alignment: Alignment.center,
        child: AnswerHandwritingMainBox(
          jobId: jobId,
          studentId: studentId,
          pageNum: pageNum,
          questionNo: questionNo,
          closeCall: closeCall,
        ),
      ),
    );
  }
}

Future<void> showAnswerHandwriting(BuildContext context, {required int jobId, required int studentId, int? pageNum, int? questionNo}) async {
  return showDialog(
    context: context,
    builder: (BuildContext context) => AnswerHandwriting(
      jobId: jobId,
      studentId: studentId,
      pageNum: pageNum,
      questionNo: questionNo,
      closeCall: () => Navigator.of(context).pop(),
    ),
  );
}

// 主图
class AnswerHandwritingMainBox extends HookWidget {
  const AnswerHandwritingMainBox({
    required this.jobId,
    required this.studentId,
    required this.closeCall,
    this.pageNum,
    this.questionNo,
    Key? key,
  }) : super(key: key);

  final int jobId;
  final int studentId;
  final int? pageNum;
  final int? questionNo;
  final Function closeCall;

  @override
  Widget build(BuildContext context) {
    var _useStateModel = UseMainBoxState.use(jobId, studentId, pageNum, questionNo);

    useValueChanged<JobHandwriting?, void>(_useStateModel.handwritingData.value, (_, __) {
      var theData = _useStateModel.handwritingData.value;
      _useStateModel.pageNum.value = theData?.pageNum;
      _useStateModel.pageCount.value = theData?.pageCount ?? 0;
      _useStateModel.playPause.value = false;
      _useStateModel.constantFastSpeed.value = false;
      Future.delayed(Duration.zero, () {
        _useStateModel.handwritingKey.currentState?.ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
      });
      _useStateModel.handwritingDetail.value = _useStateModel.getHandwritingDetail(theData);
    });

    useValueChanged<int?, void>(_useStateModel.pageNum.value, (oldVal, __) {
      if (oldVal != null && oldVal != _useStateModel.pageNum.value) {
        _useStateModel.questionNo = null;
        _useStateModel.getData().catchError((e) => closeCall());
      }
    });

    useEffect(() {
      _useStateModel.getData().catchError((e) => closeCall());
      return () {};
    }, []);

    JobHandwriting? _data = _useStateModel.handwritingData.value;
    HandwritingInfo? _dataDetail = _useStateModel.handwritingDetail.value;

    if (_data == null || _dataDetail == null) return Container();

    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Stack(
          alignment: const FractionalOffset(0, 0.5),
          children: [
            // 图片展示主框
            HandwritingDrawBox(
              _data.paperPicture,
              _dataDetail,
              key: _useStateModel.handwritingKey,
            ),
            $PageNumberBox(_data.pageNum, _data.pageCount),
            // 上一页按钮
            $PreviousNutton(
              _useStateModel.pageNum.value,
              () => _useStateModel.pageNum.value = _useStateModel.pageNum.value! - 1,
            ),
            // 下一题按钮
            $NextPageButton(
              _useStateModel.pageNum.value,
              _useStateModel.pageCount.value,
              () => _useStateModel.pageNum.value = _useStateModel.pageNum.value! + 1,
            ),
          ],
        ),
        $BottomPlaybar(_dataDetail.timeConsuming, _dataDetail.pauseCount, _dataDetail.pauseInterval),
      ],
    );
  }
}

class UseMainBoxState with CommonMixin {
  final int jobId;
  final int studentId;
  int? questionNo;
  final ValueNotifier<int?> pageNum;
  final ValueNotifier<int> pageCount;
  final ValueNotifier<JobHandwriting?> handwritingData;
  final ValueNotifier<HandwritingInfo?> handwritingDetail;

  final ValueNotifier<bool> playPause; // 播放暂停
  final ValueNotifier<bool> constantFastSpeed; // 原速、快速  默认原速

  GlobalKey<_HandwritingDrawBoxState> handwritingKey;

  UseMainBoxState._({
    required this.jobId,
    required this.studentId,
    required this.pageNum,
    required this.handwritingData,
    required this.questionNo,
    required this.pageCount,
    required this.playPause,
    required this.constantFastSpeed,
    required this.handwritingDetail,
    required this.handwritingKey,
  });

  // 工厂构造函数
  factory UseMainBoxState.use(int jobId, int studentId, [int? pageNum, int? questionNo]) {
    return UseMainBoxState._(
      jobId: jobId,
      studentId: studentId,
      questionNo: questionNo,
      pageNum: useState(pageNum),
      handwritingData: useState(null),
      handwritingDetail: useState(null),
      pageCount: useState(0),
      playPause: useState(false),
      constantFastSpeed: useState(false),
      handwritingKey: GlobalKey(),
    );
  }

  Future getData() async {
    try {
      ToastUtils.showLoading();
      var _client = await getClient();
      var res = await _client.getHandwriting(jobId, studentId, questionNo, pageNum.value);
      if (res?.success ?? false) {
        handwritingData.value = res!.data;
        if (handwritingData.value!.lattices.isEmpty) {
          Future.delayed(Duration.zero, () => ToastUtils.showInfo('此页试题没有笔迹'));
        }
        return;
      }
      Future.delayed(Duration(seconds: 1), () => ToastUtils.showError(res?.message ?? '笔记数据请求失败'));
    } catch (e) {
      print(e);
    } finally {
      ToastUtils.dismiss();
    }
  }

  HandwritingInfo? getHandwritingDetail(JobHandwriting? theData) {
    if (theData == null) return null;
    // 笔画分组
    // var lattices = Map<int, List<Lattices>>.fromIterable(
    //   theData.lattices,
    //   key: (key) => key.stroke,
    //   value: (value) {
    //     // return theData.lattices.where((item) => item.stroke == value.stroke).toList()..sort((a, b) => a.time.compareTo(b.time));
    //     return theData.lattices.where((item) => item.stroke == value.stroke).toList();
    //   },
    // );
    var lattices = Map<int, List<Lattices>>();
    var theLattices = theData.lattices;
    for (var i = 0; i < theLattices.length; i++) {
      Lattices item = theLattices[i];
      if (!lattices.containsKey(item.stroke)) lattices[item.stroke] = [];
      lattices[item.stroke]!.add(item); // 添加笔画数据
    }

    List<int> latticeKeys = lattices.keys.toList();
    int timeConsuming = 0;
    if (latticeKeys.isNotEmpty) {
      List<Lattices>? firstAction = lattices[latticeKeys[0]];
      List<Lattices>? lastAction = lattices[latticeKeys[latticeKeys.length - 1]];
      int firstTime = 0;
      int lastTime = 0;

      if (firstAction?.isNotEmpty ?? false) {
        // 第一个笔画集合
        firstTime = firstAction![0].time;
      }
      if (lastAction?.isNotEmpty ?? false) {
        // 最后一笔画集合
        lastTime = lastAction![0].time;
      }
      timeConsuming = lastTime - firstTime;
    }
    var pauseCount = 0; // 停顿次数
    List<PauseIntervalTime> pauseInterval = [];
    for (var i = 0; i < latticeKeys.length; i++) {
      var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合
      var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合
      for (var j = 0; j < currentLattices.length; j++) {
        var intervalTime = 0;
        var lattice = currentLattices[j];

        if (j != 0) {
          var prevItem = currentLattices[j - 1];
          var adjacentSpacingTime = lattice.time - prevItem.time;
          intervalTime = adjacentSpacingTime + prevItem.intervalTime;
          if (adjacentSpacingTime > 5000) {
            // 大于5秒算一次停顿
            pauseCount++;
            pauseInterval.add(PauseIntervalTime(startTime: prevItem.intervalTime, endTime: intervalTime));
          }
        } else {
          if (i != 0 && prevLattices != null) {
            var prevLatticeLastItem = prevLattices[prevLattices.length - 1];
            var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time;
            intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime;
            if (adjacentSpacingTime > 5000) {
              // 大于5秒算一次停顿
              pauseCount++;
              pauseInterval.add(PauseIntervalTime(startTime: prevLatticeLastItem.intervalTime, endTime: intervalTime));
            }
          }
        }
        lattice.intervalTime = intervalTime;
      }
    }
    return HandwritingInfo(pauseCount, timeConsuming, lattices, pauseInterval);
  }
}

class HandwritingInfo {
  int pauseCount; // 停顿次数
  List<PauseIntervalTime> pauseInterval;
  int timeConsuming; // 耗时（毫秒）
  Map<int, List<Lattices>> strokeMap; // 笔画数据

  HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap, this.pauseInterval);
}

// 图片展示
@hwidget
Widget $theCachedNetworkImage(ImageWidgetBuilder imageBuilder, {required String imageUrl}) {
  UseCachedImgRefresh _useImgRefsh = UseCachedImgRefresh.use();

  return CachedNetworkImage(
    key: _useImgRefsh.imageKey.value,
    fit: BoxFit.contain,
    imageUrl: imageUrl,
    imageBuilder: imageBuilder,
    placeholder: (context, url) => Center(child: SpinKitWaveSpinner(color: Theme.of(context).primaryColor, size: 50.r)),
    errorWidget: (context, url, error) {
      return GestureDetector(
        onTap: () => (_useImgRefsh.imageKey.value = UniqueKey()),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Image.asset('assets/images/test_paper_loading_failed.png'),
            quickText('加载失败，点击重试', color: Color.fromRGBO(148, 163, 182, 1), size: 12.sp),
          ],
        ),
      );
    },
  );
}

/// 上一页
@swidget
Widget $previousNutton(BuildContext context, int? pageNum, Function call) {
  if (pageNum != null && pageNum > 1)
    return Positioned(
      left: 3.w,
      child: FloatingActionButton(
        heroTag: '点击前往上一题',
        tooltip: '点击前往上一题',
        focusColor: Theme.of(context).primaryColor,
        backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1),
        elevation: 6.r,
        onPressed: () => easyThrottle('answer_handwriting_previous', () => call()),
        child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp),
      ),
    );

  return SizedBox();
}

/// 下一页
@swidget
Widget $nextPageButton(BuildContext context, int? pageNum, int totalNum, Function call) {
  if (pageNum != null && pageNum < totalNum)
    return Positioned(
      right: 3.w,
      child: FloatingActionButton(
        heroTag: '点击前往下一题',
        tooltip: '点击前往下一题',
        elevation: 6.r,
        backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1),
        onPressed: () => easyThrottle('answer_handwriting_next', () => call()),
        child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
      ),
    );

  return SizedBox();
}

// 笔记还原主框
class HandwritingDrawBox extends StatefulHookConsumerWidget {
  final String image;
  final HandwritingInfo handwritingData;
  // final double boxWidth;
  // final double boxHeight;
  const HandwritingDrawBox(this.image, this.handwritingData, {super.key});

  @override
  ConsumerState<HandwritingDrawBox> createState() => _HandwritingDrawBoxState();
}

class _HandwritingDrawBoxState extends ConsumerState<HandwritingDrawBox> with EventBusMixin {
  ImageStream? imageStream; // 图片监听数据
  TestQuestionsImageInfo? imagInfoModel; // 试题图片数据
  late ImageStreamListener theImageStreamListener;

  late ValueNotifier<List<GestureHandwritingRecording>> _vnHandWritings;

  late RemoveListener _jobHandwritingDrawingTrajectoryListener; // 批注关闭监听
  List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = [];
  List<GestureHandwritingRecording> _packagedHandwritingDataAll = [];
  List<GestureHandwritingRecording> pendingData = []; // 待执行数据
  List<Timer> timers = [];
  int handwritingTime = 0;
  int handwritingDuration = 0;
  double speed = 1; // 播放速度
  @override
  void initState() {
    super.initState();
    _vnHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]);
    _jobHandwritingDrawingTrajectoryListener = ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).addListener((state) {
      _vnHandWritings.value = state;
    }, fireImmediately: false);
    eventOn(callback: (e) {
      switch (e.runtimeType) {
        case JobHandwritingRunTimeBus:
          var _model = (e as JobHandwritingRunTimeBus);
          var _runtime = _model.runTimeVal;
          handwritingDuration = _model.totalVal;
          handwritingTime = _runtime;
          if (_runtime <= 0) {
            pendingData.clear();
          }
          break;
        case JobHandwritingDragProgressBarBus:
          var _model = (e as JobHandwritingDragProgressBarBus);
          dragProgressBarInitData(_model.changeVal, _model.totalVal);
          break;
        case JobHandwritingPlaybarBus:
          // 播放 暂停
          var _val = e as JobHandwritingPlaybarBus;
          if (_val.play) {
            // 播放
            toGoPlay();
          } else {
            // 暂停
            toGoPause(_val.recalculate);
          }
          break;
        case PlaybackSpeedBus:
          // 播放速度
          var _model = (e as PlaybackSpeedBus);
          speed = _model.speed;
          dragProgressBarInitData(handwritingDuration - handwritingTime, handwritingDuration);
          break;
        default:
      }
    });

    theImageStreamListener = ImageStreamListener((ImageInfo info, bool _) {
      if (imagInfoModel != null) return;
      imagInfoModel = TestQuestionsImageInfo(
        // 获取图片的宽高
        boxHeight: ScreenUtil().scaleHeight, // 图片展示自适应所以 这里无法获取容器的高度
        boxWidth: ScreenUtil().screenWidth - 60.r,
        url: widget.image,
        height: info.image.height.toDouble(),
        width: info.image.width.toDouble(),
      )..calculateStartAndEndHeight(60.h); // 60.h是底部的播放栏高度
      getCalculatedSize();
    });
  }

  @override
  void dispose() {
    timers.forEach((e) {
      if (e.isActive) e.cancel();
    });
    _jobHandwritingDrawingTrajectoryListener();
    _vnHandWritings.dispose();
    try {
      imageStream?.removeListener(theImageStreamListener);
      eventCancel();
    } catch (e) {}
    super.dispose();
  }

  // 暂停播放
  Future<void> toGoPause(bool recalculate) async {
    timers.forEach((e) {
      if (e.isActive) e.cancel();
    });
    timers = [];
    // 总时间-剩余时间=已经执行时间
    if (recalculate && pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) {
      // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间
      pendingData = pendingData.map((e) {
        return GestureHandwritingRecording(
          stroke: e.stroke,
          data: e.data,
          usageTime: e.usageTime,
          intervalTime: e.intervalTime - (handwritingDuration - handwritingTime) * 1000,
        );
      }).toList();
    }
  }

  /// 拖动进度条后重新初始化数据
  /// @param startTime 起始时间 单位秒
  Future<void> dragProgressBarInitData(int startTime, int totalDuration) async {
    eventFire(model: JobHandwritingPlaybarBus(false, false));
    timers.forEach((e) {
      if (e.isActive) e.cancel();
    });
    timers = [];
    pendingData.clear();

    if (startTime == 0) {
      ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
      pendingData.addAll(_packagedHandwritingDataAll);
    } else {
      // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间
      startTime = startTime * 1000; // 转为毫秒
      List<GestureHandwritingRecording> executeImmediately = []; // 立即执行数据
      List<GestureHandwritingRecording> waitingExecution = []; // 等待执行数据

      for (var i = 0; i < _packagedHandwritingDataAll.length; i++) {
        var item = _packagedHandwritingDataAll[i];

        if (item.intervalTime < startTime) {
          // 需要直接装配到直接打印的容器
          executeImmediately.add(item);
        } else {
          var intervalTime = item.intervalTime - startTime;
          // 需要等待的数据
          waitingExecution.add(GestureHandwritingRecording(
            stroke: item.stroke,
            data: item.data,
            usageTime: item.usageTime,
            intervalTime: intervalTime,
          ));
        }
      }

      pendingData = waitingExecution;
      ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(executeImmediately);
    }
    eventFire(model: JobHandwritingPlaybarBus(true));
  }

  Future<void> zhixinCall(GestureHandwritingRecording e) async {
    if (mounted) {
      List<GestureHandwritingRecording> trajectorys = ref.read(jobHandwritingDrawingTrajectoryProvider)..add(e);
      ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal(List.from(trajectorys));
      pendingData.remove(e); // 执行后删除容器中的当前动作
    }
  }

  /// 开始播放
  Future<void> toGoPlay() async {
    try {
      var executableData = _packagedHandwritingDataAll;
      if (pendingData.isNotEmpty) {
        // 待执行的数据没有执行完成 就继续执行待执行数据
        executableData = pendingData;
      } else {
        pendingData.addAll(_packagedHandwritingDataAll);
        ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
      }

      executableData.forEach((e) {
        var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e));
        timers.add(ter);
      });
    } catch (e) {
      print('播放报错：$e');
    }
  }

  // 计算尺寸
  Future<void> getCalculatedSize() async {
    if (imagInfoModel == null) return;
    var dataInfo = widget.handwritingData;
    Map<int, List<Lattices>> mapData = dataInfo.strokeMap;
    if (mapData.isNotEmpty) {
      List<int> keys = mapData.keys.toList();

      for (var i = 0; i < keys.length; i++) {
        List<GestureHandwritingRecording> newTrajectoryData = mapData[keys[i]]!.map((e) {
          double theX = e.x * imagInfoModel!.scale!;
          double theY = e.y * imagInfoModel!.scale!;

          return GestureHandwritingRecording(
            data: Offset(theX, theY),
            usageTime: e.time.toInt(),
            intervalTime: e.intervalTime,
            stroke: e.stroke,
          );
        }).toList();

        newTrajectoryData.sort((a, b) => a.usageTime.compareTo(b.usageTime));

        _packagedHandwritingDatas.add(newTrajectoryData); // 分组数据
        _packagedHandwritingDataAll.addAll(newTrajectoryData); // 不分组数据
      }
      Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); // 通知外部可以播放笔迹
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      child: RepaintBoundary(
        child: CustomPaint(
          willChange: true,
          isComplex: true,
          foregroundPainter: HandWritingDrawingPainter(ctrl: _vnHandWritings),
          // size: Size(ScreenUtil().screenWidth - 60.r, widget.boxHeight),
          child: RepaintBoundary(
            child: $TheCachedNetworkImage(
              imageUrl: widget.image,
              (context, imageProvider) {
                Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain);
                if (imagInfoModel == null) {
                  imageStream?.removeListener(theImageStreamListener);
                  // 视图中展示图片的尺寸计算获取
                  imageStream = imageWidget.image.resolve(ImageConfiguration());
                  imageStream?.addListener(theImageStreamListener);
                }

                return imageWidget;
              },
            ),
          ),
        ),
      ),
    );
  }
}

class HandWritingDrawingPainter extends CustomPainter {
  final ValueNotifier<List<GestureHandwritingRecording>> ctrl;
  HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl);
  //[定义画笔]
  final Paint paintBrush = Paint()
    //画笔颜色
    ..color = Colors.black
    //画笔笔触类型
    ..strokeCap = StrokeCap.round
    //是否启动抗锯齿
    ..isAntiAlias = true
    //绘画风格，默认为填充
    // ..style = PaintingStyle.fill
    //画笔的宽度
    ..style = PaintingStyle.stroke
    ..strokeWidth = 0.5.r;

  @override
  void paint(Canvas canvas, Size size) {
    // canvas.drawPoints(PointMode.points, thePoints, paintBrush);
    canvas.save();

    var points = ctrl.value;
    var _length = points.length;
    for (int i = 0; i < _length; i++) {
      GestureHandwritingRecording item = points[i];
      GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null;

      Offset offsetData = item.data;
      Offset? nextOffsetData = nextItem?.data;
      if (nextOffsetData != null && item.stroke == nextItem?.stroke) {
        canvas.drawLine(offsetData, nextOffsetData, paintBrush);
      }
    }
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    if (oldDelegate is HandWritingDrawingPainter) {
      var repaint = ctrl.value.length != oldDelegate.ctrl.value.length || oldDelegate.ctrl.value != ctrl.value;
      print('调用是否绘制：$repaint');
      return repaint;
    }
    return true; // 如果 oldDelegate 不是 MyCustomPainter 的实例，则总是重绘
  }
}

@swidget
Widget $pageNumberBox(int pageNum, int totalNum) {
  return Positioned(
    top: 6.h,
    right: 4.w,
    child: Container(
        padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
        decoration: BoxDecoration(
          color: Color.fromRGBO(0, 0, 0, 0.47),
          borderRadius: BorderRadius.circular(5.r),
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            quickText('$pageNum', color: Colors.white, size: 11.sp, align: TextAlign.end),
            quickText('/', color: Colors.white, size: 10.sp, align: TextAlign.end),
            quickText('$totalNum', color: Colors.white, size: 8.sp, align: TextAlign.end),
          ],
        )),
  );
}

@hwidget
Widget $bottomPlaybar(BuildContext context, int timeConsuming, int pauseCount, List<PauseIntervalTime> pauseIntervals) {
  var usePlaybar = UseBottomPlaybar.use(timeConsuming);
  useValueChanged<int, void>(timeConsuming, (_, __) {
    usePlaybar.playTimingSuspend();
    usePlaybar.playPause.value = false;
    var seds = timeConsuming ~/ 1000;
    if ((timeConsuming % 1000) > 500) seds += 1;
    usePlaybar.handwritingDuration.value = seds;
    usePlaybar.constantFastSpeed.value = PlaybackSpeed.ORIGINAL_SPEED;
  });

  useValueChanged<int, void>(usePlaybar.handwritingDuration.value, (_, __) {
    usePlaybar.useTime.value = usePlaybar.handwritingDuration.value;
  });
  // 播放速度
  useValueChanged<PlaybackSpeed, void>(usePlaybar.constantFastSpeed.value, (_, __) {
    usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed));
    // 播放速度变化
    usePlaybar.playTimingSuspend();
    usePlaybar.playTimingStarts();
  });
  // 计时结束监听
  useValueChanged<int, void>(usePlaybar.useTime.value, (_, __) {
    var _runtime = usePlaybar.useTime.value;
    if (_runtime <= 0 || usePlaybar.handwritingDuration.value == _runtime) {
      Future.delayed(Duration.zero, () => (usePlaybar.playPause.value = false)); // 初始化播放按钮
    }
    usePlaybar.eventFire(model: JobHandwritingRunTimeBus(_runtime, usePlaybar.handwritingDuration.value));
  });

  useEffect(() {
    usePlaybar.eventOn(callback: (e) {
      switch (e.runtimeType) {
        case JobHandwritingPlaybarBus:
          // 出发播放暂停
          var _val = e as JobHandwritingPlaybarBus;
          if (_val.play) {
            // 开始播放
            usePlaybar.playTimingStarts();
            if (!usePlaybar.playPause.value) usePlaybar.playPause.value = true;
          } else {
            // 暂停播放
            usePlaybar.playTimingSuspend();
            if (usePlaybar.playPause.value) usePlaybar.playPause.value = false;
          }
          break;
        case JobHandwritingGetReadyBus:
          // 作业笔迹已经计算好坐标 可以开始播放
          Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true));
          break;
        default:
      }
    });

    return () {
      try {
        usePlaybar.eventCancel();
        usePlaybar.timer.value?.cancel();
      } catch (e) {
        print(e);
      }
    };
  }, []);

  return Container(
    height: 60.h,
    padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
    alignment: Alignment.center,
    color: Color.fromRGBO(0, 0, 0, 0.4),
    child: Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        if (usePlaybar.handWritingReady.value)
          InkWell(
            onTap: () => easyThrottle('job_handwriting_play_pause', () {
              if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹');

              usePlaybar.playPause.value = !usePlaybar.playPause.value;
              usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
            }),
            child: Icon(
              !usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline,
              color: Colors.white,
              size: 28.r,
            ),
          )
        else
          SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white),
        SizedBox(width: 6.w),
        Expanded(
          child: LayoutBuilder(builder: (context, constraints) {
            final double containerWidth = constraints.maxWidth; // 展示区域总宽度
            var unitScale = containerWidth / timeConsuming; // 单位刻度
            var pauseIntervalsLength = pauseIntervals.length;

            List<Widget> pauseTickMarks = pauseIntervals.asMap().keys.map((e) {
              bool isLast = e == pauseIntervalsLength - 1;
              bool isFirst = e == 0;
              var item = pauseIntervals[e];
              return Positioned(
                top: 0,
                left: unitScale * item.startTime,
                child: Container(
                  width: unitScale * (item.apart ?? 0),
                  height: 8.h,
                  decoration: BoxDecoration(
                    color: Color.fromRGBO(202, 201, 201, 1),
                    borderRadius: isFirst
                        ? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r))
                        : (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null),
                  ),
                ),
              );
            }).toList();

            return Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Stack(
                  children: [
                    Container(
                      height: 8.h,
                      width: containerWidth,
                      decoration: BoxDecoration(
                        // color: Color.fromRGBO(146, 146, 146, 1),
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(50.r),
                      ),
                    ),
                    ...pauseTickMarks,
                    Container(
                      height: 8.h,
                      width: containerWidth,
                      // color: Theme.of(context).primaryColor,
                      child: SliderTheme(
                        data: SliderTheme.of(context).copyWith(
                          trackHeight: 8.h, // 轨道高度
                          trackShape: RoundedRectSliderTrackShape(), // 轨道形状，可以自定义
                          activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色
                          inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色
                          thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0),
                          thumbColor: Colors.white, // 滑块颜色
                          overlayShape: RoundSliderOverlayShape(overlayRadius: 0),
                          overlayColor: Colors.black54, // 滑块外圈颜色
                          // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状，可以自定义
                        ),
                        child: Slider(
                          value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(),
                          min: 0.0,
                          max: usePlaybar.handwritingDuration.value.toDouble(),
                          inactiveColor: Colors.transparent,
                          onChangeEnd: (value) {
                            if (!usePlaybar.handWritingReady.value) return;
                            usePlaybar.playTimingSuspend(); // 暂停计时器得暂停
                            usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value));
                            usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
                          },
                          onChanged: (double value) {
                            if (!usePlaybar.handWritingReady.value) return;
                            usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
                          },
                        ),
                      ),
                    ),
                  ],
                ),
                SizedBox(height: 4.h),
                SizedBox(
                  width: containerWidth,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      quickText('累计停顿：$pauseCount次', color: Colors.white, size: 7.sp),
                      quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp),
                    ],
                  ),
                )
              ],
            );
          }),
        ),
        SizedBox(width: 16.w),
        InkWell(
          onTap: () => easyThrottle('job_handwriting_speed', () {
            var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
            if (theIndex == PlaybackSpeed.values.length - 1) {
              theIndex = -1;
            }
            usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
          }, duration: Duration(milliseconds: 500)),
          child: Container(
            // alignment: Alignment.,
            padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
            decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
            child: quickText(
              '${usePlaybar.constantFastSpeed.value.name}',
              color: Color.fromRGBO(79, 114, 244, 1),
              size: 8.sp,
              align: TextAlign.center,
            ),
          ),
        ),
      ],
    ),
  );
}

class SysjTime extends StatefulWidget {
  const SysjTime({super.key});

  @override
  State<SysjTime> createState() => _SysjTimeState();
}

class _SysjTimeState extends State<SysjTime> with EventBusMixin<JobHandwritingRunTimeBus> {
  int useTime = 0;
  @override
  void initState() {
    super.initState();
    eventOn(callback: (JobHandwritingRunTimeBus e) {
      useTime = e.runTimeVal;
      toUpState(setState, () {}, mounted);
    });
  }

  @override
  void dispose() {
    eventCancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return quickText(convertSeconds(useTime)?.toString() ?? '', color: Colors.white, size: 7.sp);
  }
}

class UseBottomPlaybar with EventBusMixin {
  final ValueNotifier<int> handwritingDuration; // 笔迹总时长
  final ValueNotifier<bool> playPause; // 播放暂停
  final ValueNotifier<PlaybackSpeed> constantFastSpeed; // 原速、快速  默认原速
  final ValueNotifier<bool> handWritingReady;

  final ValueNotifier<int> useTime; // 耗时 单位：（秒）

  final ValueNotifier<Timer?> timer;

  UseBottomPlaybar._(
      {required this.handWritingReady,
      required this.handwritingDuration,
      required this.playPause,
      required this.constantFastSpeed,
      required this.useTime,
      required this.timer});

  // 工厂构造函数
  factory UseBottomPlaybar.use(int milliseconds) {
    int handwritingDuration = milliseconds ~/ 1000;
    if ((milliseconds % 1000) > 500) handwritingDuration += 1;
    return UseBottomPlaybar._(
      playPause: useState(false),
      constantFastSpeed: useState(PlaybackSpeed.ORIGINAL_SPEED),
      useTime: useState(handwritingDuration),
      timer: useState(null),
      handwritingDuration: useState(handwritingDuration),
      handWritingReady: useState(false),
    );
  }

  /// 开始计时
  void playTimingStarts() {
    if (useTime.value > 0) {
      timer.value?.cancel();

      timer.value = Timer.periodic(Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), (theTime) {
        useTime.value -= 1;
        if (useTime.value < 0) {
          theTime.cancel();
          timer.value?.cancel();
          timer.value = null;
          useTime.value = handwritingDuration.value;
        }
      });
    }
  }

  /// 暂停
  void playTimingSuspend() {
    timer.value?.cancel();
    timer.value = null;
  }
}

// 播放按钮
class JobHandwritingPlaybarBus {
  bool play;
  bool recalculate;
  JobHandwritingPlaybarBus(this.play, [this.recalculate = true]);
}

// 笔迹是否已经准备好(笔迹计算好坐标后通知通知栏可以开始播放)
class JobHandwritingGetReadyBus {
  JobHandwritingGetReadyBus();
}

// 笔记运行时间
class JobHandwritingRunTimeBus {
  int runTimeVal;
  int totalVal;
  JobHandwritingRunTimeBus(this.runTimeVal, this.totalVal);
}

// 拖动进度条
class JobHandwritingDragProgressBarBus {
  int changeVal;
  int totalVal;
  JobHandwritingDragProgressBarBus(this.changeVal, this.totalVal);
}

// 播放速度 （原速播放/快速播放）
class PlaybackSpeedBus {
  double speed;
  PlaybackSpeedBus(this.speed);
}

// 播放倍速
enum PlaybackSpeed {
  ORIGINAL_SPEED(name: '原速播放', speed: 1),
  ONE_POINT_FIVE_SPEED(name: '1.5x播放', speed: 1.5),
  DOUBLE_SPEED(name: '2.0x播放', speed: 2),
  TRIPLE_SPEED(name: '3.0x播放', speed: 3),
  FOUR_SPEED(name: '4.0x播放', speed: 4),
  FIVE_SPEED(name: '5.0x播放', speed: 5),
  SIX_SPEED(name: '6.0x播放', speed: 6);

  const PlaybackSpeed({required this.name, required this.speed});
  final double speed;
  final String name;
}

@JsonSerializable()
class PauseIntervalTime extends Object {
  int? apart;
  int startTime;
  int endTime;
  PauseIntervalTime({required this.startTime, required this.endTime}) {
    apart = endTime - startTime;
  }

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

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