import 'dart:typed_data';
import 'dart:ui';
// ignore: avoid_web_libraries_in_flutter
import 'dart:js';
import 'dart:async';

import 'package:fis_lib_media_rt/base/capturer.dart';
import 'package:fis_lib_media_rt/utils/js_lib_import.dart';
import 'package:vid/us/vid_us_image_data.dart';

import '../channel/base.dart';
import '../values.dart';

class NTCapturer extends BaseCapturer {
  /// 录制采样速率
  static const int recordRate = 20;

  late final NTChannelMixin ntChannel;

  /// 录制开始时间
  DateTime recordStartTime = DateTime.now();

  /// 裁图区域
  Rect _cropArea = const Rect.fromLTWH(0, 0, 2 / 3, 2 / 3);

  /// 是否需要裁图
  bool _isNeedCrop = false;

  VidUsImageData? imageData4Record;

  NTCapturer({required super.channel}) {
    ntChannel = channel as NTChannelMixin;
  }

  JsObject get _ctx => context['rtmpCapturer'];

  @override
  Future<void> initCapturer({
    int? width,
    int? height,
    bool isNeedCrop = false,
    Rect? cropArea,
  }) async {
    await _importJSLib();

    print("RTMP📹初始化通道, channel_viewId: ${ntChannel.viewId}");
    final elementId = "$IFRAME_ID_PREFIX${ntChannel.viewId}";
    JsArray<dynamic> videoSize = _ctx.callMethod("init", [elementId]);
    frameWidth = videoSize[0];
    frameHeight = videoSize[1];
    if (frameWidth == 0 || frameHeight == 0) {
      print("RTMP📹初始化失败，请检查通道状态");
      disposeJsVideoCapture();
    } else {
      isInit = true;
      _isNeedCrop = isNeedCrop;
      _cropArea = cropArea ?? _cropArea;
      if (isNeedCrop) {
        _ctx.callMethod(
          'setClipSize',
          [frameWidth * _cropArea.width, frameHeight * _cropArea.height],
        );
      }
    }
  }

  @override
  Future<VidUsImageData> captureFrame() async {
    if (!isInit) return Future.error('Capturer is not init');
    VidUsImageData imageData = VidUsImageData.empty(1, VidUsImageFormat.Jpeg);
    Uint8List jpegBytes = await captureOneFrameAsync();
    imageData.addJpegImage(jpegBytes, frameWidth, frameHeight);

    disposeJsVideoCapture();
    return imageData;
  }

  @override
  void startRecord() async {
    if (!isInit) return;
    if (isRecording) return;
    imageData4Record = VidUsImageData.empty(recordRate, VidUsImageFormat.Jpeg);
    isRecording = true;
    recordStartTime = DateTime.now();
    const int captureInterval = 1000 ~/ recordRate;
    while (isRecording) {
      await Future.delayed(const Duration(milliseconds: captureInterval));
      Uint8List jpegBytes = await captureOneFrameAsync();
      imageData4Record!.addJpegImage(jpegBytes, frameWidth, frameHeight);
    }
  }

  @override
  Future<VidUsImageData> stopRecord() async {
    if (!isRecording) return Future.error('Record not start');

    isRecording = false;
    int recordDurationMS = DateTime.now().millisecondsSinceEpoch -
        recordStartTime.millisecondsSinceEpoch;
    // print("✨ 结束录制 总录制时长 ${recordDurationMS / 1000}s 开始生成 vid");

    // 截图结束一秒后执行，保证所有截图都已保存
    await Future.delayed(const Duration(milliseconds: 1000));
    int fps = (imageData4Record!.imageCount * 1000 / recordDurationMS).round();
    imageData4Record!.setThirdPartFPS(fps);

    print("✨ 总帧数 ${imageData4Record!.imageCount} 帧率 $fps");

    disposeJsVideoCapture();
    return imageData4Record!;
  }

  @override
  void dispose() {
    if (isRecording) {
      stopRecord();
    }
    if (imageData4Record != null) {
      imageData4Record = null;
    }
    disposeJsVideoCapture();
  }

  /// 利用 complete 保证异步执行完毕
  Future<Uint8List> captureOneFrameAsync() async {
    Completer<Uint8List> captureComplete = Completer<Uint8List>();
    try {
      _ctx.callMethod("captureOne").callMethod("then", [
        (result) {
          captureComplete.complete(result);
        }
      ]).callMethod("catch", [
        (error) {
          captureComplete.completeError(error);
        }
      ]);
    } catch (e) {
      captureComplete.completeError(e);
    }
    return await captureComplete.future;
  }

  /// 释放资源
  void disposeJsVideoCapture() {
    _ctx.callMethod('release');
  }

  static Future<void> _importJSLib() {
    return JsLibraryImportUtil.import(
        "./wwwroot/js/rtmp_video_capture_wrapper.js");
  }
}
