import 'dart:io';

import 'package:fis_lib_media_rt/base/capturer.dart';
import 'package:fis_lib_media_rt/implementations/trtc/player.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:image_crop_plus/image_crop_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tencent_trtc_cloud/trtc_cloud.dart';
import 'package:vid/us/vid_us_image_data.dart';

import '../channel.dart';
import '../client_getter_mixin.dart';

/// 移动端捕获截图前需要先初始化存储路径，然后获取到 flutter 组件的宽高作为截图的宽高，然后方可开始截图或录制
/// 录制多帧时，移动端的方案是录制过程中会不断的截图并保存到指定路径下，然后再将所有截图转为 vid，利用录制时长和最终得到的截图数量来计算出FPS
class TrtcCapturer extends BaseCapturer with TrtcClientGetterMixin {
  late final TrtcChannelMixin trtcChannel;

  /// 移动端文件缓存路径
  String? recordStoragePath;

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

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

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

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

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

  @override
  Future<void> initCapturer(
      {int? width,
      int? height,
      bool isNeedCrop = false,
      Rect? cropArea}) async {
    _isNeedCrop = isNeedCrop;
    _cropArea = cropArea ?? _cropArea;
    frameWidth = width ?? 640;
    frameHeight = height ?? 480;
    if (frameWidth == 0 && frameHeight == 0) {
      print("📹初始化失败，请检查摄像头状态");
    } else {
      isInit = true;
    }
  }

  @override
  Future<VidUsImageData> captureFrame() async {
    if (!isInit) return Future.error('Capturer is not init');
    final path = await getFileStorageDir();
    if (path == null) return Future.error('File storage path is null');
    String suffix = DateTime.now().millisecondsSinceEpoch.toString();
    await client.snapshotVideo(
      trtcChannel.isLocal ? null : channel.member.userId,
      0,
      "$path/${suffix}_temp.jpg",
    );

    /// 等待1s
    await Future.delayed(const Duration(seconds: 1));

    /// 读取该文件，并转为vid
    File file = File("$path/${suffix}_temp.jpg");
    File croppedFile;
    croppedFile = _isNeedCrop ? await _cropImage(file) : file;
    final options = await ImageCrop.getImageOptions(file: croppedFile);
    Uint8List jpgBytes = await croppedFile.readAsBytes();

    /// 创建空的 vid (默认10帧)
    VidUsImageData imageData = VidUsImageData.empty(10, VidUsImageFormat.Jpeg);
    imageData.addJpegImage(jpgBytes, options.width, options.height);
    cleanCache();
    return imageData;
  }

  @override
  void startRecord() async {
    if (!isInit) return;
    if (isRecording) return;
    recordStoragePath = await getFileStorageDir();
    if (recordStoragePath == null) return;
    isRecording = true;
    recordStartTime = DateTime.now();
    const int captureInterval = 1000 ~/ recordRate;
    while (isRecording) {
      await Future.delayed(const Duration(milliseconds: captureInterval));
      String suffix = DateTime.now().millisecondsSinceEpoch.toString();
      String filePath = "$recordStoragePath/${suffix}_temp.jpg";
      await client.snapshotVideo(
        trtcChannel.isLocal ? null : channel.member.userId,
        0,
        filePath,
      );
    }
  }

  @override
  Future<VidUsImageData> stopRecord() async {
    if (!isRecording) return Future.error('Record not start');
    isRecording = false;
    int recordDurationMS = DateTime.now().millisecondsSinceEpoch -
        recordStartTime.millisecondsSinceEpoch;

    /// 等待1s
    // 截图结束一秒后执行，保证所有截图都已保存
    await Future.delayed(const Duration(milliseconds: 1000));
    VidUsImageData vidBytes =
        await createVidFromPath(recordStoragePath!, recordDurationMS);
    cleanCache();
    return vidBytes;
  }

  /// 获取保存路径下的所有 JPG 文件，返回 vid
  Future<VidUsImageData> createVidFromPath(
      String path, int recordDurationMS) async {
    final Directory dir = Directory(path);
    final List<FileSystemEntity> list = dir.listSync();
    VidUsImageData imageData = VidUsImageData.empty(1, VidUsImageFormat.Jpeg);
    int imagesCount = 0;
    for (var item in list) {
      if (item.path.endsWith(".jpg")) {
        File file = File(item.path);
        File croppedFile = _isNeedCrop ? await _cropImage(file) : file;
        final options = await ImageCrop.getImageOptions(file: croppedFile);
        Uint8List jpgBytes = await croppedFile.readAsBytes();
        imageData.addJpegImage(jpgBytes, options.width, options.height);
        imagesCount++;
      }
    }

    int fps = (imagesCount * 1000 / recordDurationMS).round();
    imageData.setThirdPartFPS(fps);
    print("✨录制结束 📹总录制时长 $recordDurationMS 获取的图片数量 $imagesCount 计算得实际帧率 $fps");
    return imageData;
  }

  /// 递归清理所有包含 vid_capture 的文件夹
  Future<void> cleanCache() async {
    String tempDir = await getVidCaptureDir();
    final path = tempDir;
    await deleteFilesWithPattern(path, "temp");
  }

  Future<String?> getFileStorageDir() async {
    String tempDir = await getVidCaptureDir();
    String suffix = DateTime.now().millisecondsSinceEpoch.toString();
    final String parentPath = "${suffix}_vid_capture_temp";
    final String dirPath = "$tempDir/$parentPath";
    Directory(dirPath).createSync(recursive: true);
    return dirPath;
  }

  /// Vid Capture 专属临时目录
  Future<String> getVidCaptureDir() async {
    Directory tempDir = await getTemporaryDirectory();
    return "${tempDir.path}/vid_capture";
  }

  Future<void> deleteFilesWithPattern(String path, String pattern) async {
    final dir = Directory(path);
    if (await dir.exists()) {
      await for (var entity in dir.list(recursive: true, followLinks: false)) {
        if (entity is Directory) {
          if (entity.path.contains(pattern)) {
            await entity.delete(recursive: true);
          } else {
            await deleteFilesWithPattern(entity.path, pattern);
          }
        }
      }
    }
  }

  Future<void> listFiles(String path) async {
    final dir = Directory(path);
    if (await dir.exists()) {
      await for (var entity in dir.list(recursive: true, followLinks: false)) {
        if (entity is File) {
          print(entity.path);
        }
      }
    }
  }

  /// 裁图，返回裁图后的文件
  /// 利用 ImageCrop.cropImage 裁切1/4的图片
  /// 暂时写死裁切比例，后续可根据实际情况调整
  Future<File> _cropImage(File originFile) async {
    // final options = await ImageCrop.getImageOptions(file: originFile);
    // final sampleFile = await ImageCrop.sampleImage(
    //   file: originFile,
    //   preferredWidth: options.width,
    //   preferredHeight: options.height,
    // );
    final croppedFile = await ImageCrop.cropImage(
      file: originFile,
      area: _cropArea,
    );
    return croppedFile;
  }

  @override
  void dispose() {}
}

class WebTrtcUtil {
  static void copyMainViewToSubView(String mainViewId, String subViewId) {
    /// 由于 web 端不支持将主画面复制到子画面，所以这里直接返回
  }

  static void setTRTCPlatformViewFitMode(String viewId, String fitMode) {
    /// 由于 web 端不支持设置画面填充模式，所以这里直接返回
  }

  static void setRemoteViewToFit(String viewId) {
    /// 由于 web 端不支持设置画面填充模式，所以这里直接返回
  }

  static void setTRTCPlatformViewScaleY(String viewId, int scaleY) {
    /// 由于 web 端不支持设置画面填充模式，所以这里直接返回
  }
}
