import 'dart:async';
import 'dart:js';
import 'dart:typed_data';

import 'package:fis_lib_media_rt/base/capturer.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:vid/us/vid_us_image_data.dart';

import '../channel.dart';

/// Web 端截图则不需要初始化存储路径，需要先初始化录制，调用 initVideoCapture 获取 <video> 标签的宽高作为截图的宽高，然后方可开始截图或录制
/// Web 端的方案是录制过程中会不断的调用 captureOneFrame 方法，然后将返回的 Uint8List 转为 vid，利用录制时长和最终成功添加的图像数量来计算出FPS
class TrtcCapturer extends BaseCapturer {
  late final TrtcChannelMixin trtcChannel;

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

  /// 录制采样速率
  static const int recordRate = 20;

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

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

  VidUsImageData? imageData4Record;

  TrtcCapturer({required super.channel}) {
    trtcChannel = channel as TrtcChannelMixin;
  }

  @override
  Future<void> initCapturer(
      {int? width,
      int? height,
      bool isNeedCrop = false,
      Rect? cropArea}) async {
    print("📹初始化通道, channel: ${trtcChannel.viewId}");
    JsArray<dynamic> videoSize =
        context.callMethod('initVideoCapture', [trtcChannel.viewId]);
    frameWidth = videoSize[0];
    frameHeight = videoSize[1];
    if (frameWidth == 0 || frameHeight == 0) {
      print("📹初始化失败，请检查通道状态");
    } else {
      isInit = true;
      _isNeedCrop = isNeedCrop;
      _cropArea = cropArea ?? _cropArea;
      if (isNeedCrop) {
        context.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!;
  }

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

  /// 释放资源
  void disposeJsVideoCapture() {
    context.callMethod('disposeVideoCapture');
  }

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

class WebTrtcUtil {
  static void copyMainViewToSubView(String mainViewId, String subViewId) {
    context.callMethod('copyMainViewToSubView', [mainViewId, subViewId]);
  }

  static void setTRTCPlatformViewFitMode(String viewId, String fitMode) {
    context.callMethod('setTRTCPlatformViewFitMode', [viewId, fitMode]);
  }

  static void setRemoteViewToFit(String viewId) {
    context.callMethod('setRemoteViewToFit', [viewId]);
  }

  static void setTRTCPlatformViewScaleY(String viewId, int scaleY) {
    context
        .callMethod('setTRTCPlatformViewScaleY', [viewId, scaleY.toString()]);
  }
}
