import 'dart:async';

import 'package:file_picker/file_picker.dart';
import 'package:fis_jsonrpc/services/index.dart';
import 'package:flutter/services.dart';
import 'package:flyinsono/architecture/router/index.dart';
import 'package:flyinsono/managers/interfaces/remote_maintenance.dart';
import 'package:flyinsono/rpc.dart';
import 'package:flyinsono/views/desktop/device_live/device_live_list/controller.dart';
import 'package:flyinsono/views/desktop/device_live/device_live_list/widgets/upload_progress.dart';
import 'package:get/get.dart';

class UploadController {
  // 上传文件的最大分片大小 kb
  static const maxChunkSize = 5 * 1024 * 1024;
// 最大文件大小 kb
  static const maxFileSize = 200 * 1024 * 1024;
// 每次上传的最大分片数
  static const maxChunkCountPerBatch = 40;
  final controller = Get.find<DeviceLiveListDesktopController>();
  final manager = Get.find<IRemoteMaintenanceManager>();
  Uint8List? bytes;
  List<int> cacheBytes = [];
  int hasUploadNumber = 0;

  int totlePerBatch = 0;

  Future<StorageUploadFileInfo?> getNeedUploadFile() async {
    final result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowMultiple: false,
      allowedExtensions: ['zip'],
    );

    if (result == null || result.files.isEmpty) {
      return null;
    }
    final file = result.files.single;
    final fileName = file.name;
    final fileBytes = file.bytes!;
    final fileSize = fileBytes.length;
    return StorageUploadFileInfo(
      fileName: fileName,
      fileSize: fileSize,
      fileBytes: fileBytes,
      fileToken: '',
    );
  }

  Future<void> shellSelectFile(String path) async {
    rpc.platform.selectFile(path);
  }

  Future<List<String>> uploadFile(
    double fileSize,
    Uint8List fileBytes,
    String fileName,
  ) async {
    totlePerBatch =
        fileSize ~/ maxChunkSize + (fileSize % maxChunkSize == 0 ? 0 : 1);
    router.dialog(
      () => UploadProgressDialog(),
      dismissible: false,
    );
    if (fileSize <= maxFileSize) {
      //小文件直接上传
      return await _uploadSmallFile(fileBytes, fileName);
    } else {
      //大文件进行分批上传
      return await _uploadLargeFile(fileBytes, fileName);
    }
  }

  /// 结束合并分片
  Future<String> _mergeChunksIntoSingleFile(
    String fileName,
    List<PartFileResultInfo> chunkResults,
  ) async {
    final uploadId = chunkResults.first.uploadId;
    final resultUrl = await rpc.storage.completeMulitPartUploadFileAsync(
      //合并分块
      fileName,
      uploadId,
      chunkResults,
    );
    return resultUrl; //返回合并后的文件路径
  }

  List<Uint8List> _splitFileIntoChunks(Uint8List fileBytes) {
    final chunkSize = maxChunkSize;
    final fileSize = fileBytes.length;

    final chunks = <Uint8List>[];
    final chunkCount =
        fileSize ~/ chunkSize + (fileSize % chunkSize == 0 ? 0 : 1);

    //将文件分割成多个分块
    for (int j = 0; j < chunkCount; j++) {
      final chunk = fileBytes.sublist(
        j * chunkSize,
        (j + 1) * chunkSize < fileSize ? (j + 1) * chunkSize : fileSize,
      );
      chunks.add(chunk);
    }

    return chunks;
  }

  /// 开始分片
  Future<List<PartFileResultInfo>> _uploadChunks(
    List<Uint8List> chunks,
    String fileName, [
    int startIndex = 0,
  ]) async {
    final chunkResults = <PartFileResultInfo>[];
    String? uploadId;
    if (startIndex % maxChunkCountPerBatch == 0) {
      //初始化上传任务，获取任务编号
      uploadId = await rpc.storage.initiateMultipartUploadResult(fileName);
    }
    List<Future<PartFileResultInfo>> tasks = []; //上传任务列表
    StorageServiceSettingDTO storageServiceSetting = StorageServiceSettingDTO();
    int concurrentCount = 0; //同时上传的分片数量
    // Completer<PartFileResultInfo>? completer;

    //同时上传多个分片，加快上传速度
    for (int k = 0; k < chunks.length; k++) {
      final completer = Completer<PartFileResultInfo>();
      //循环上传每个分块
      final chunk = chunks[k];
      if (k == 0) {
        //获取上传分块所需的权限信息
        storageServiceSetting = await rpc.storage.multiPartUploadGetAuth(
          fileName,
          PartUploadFileInfo(
            partNumber: k + 1,
            uploadId: uploadId!,
            fileBytes: chunk,
          ),
        );
      }
      final task = rpc.storage.multiPartUploadAsync(
        //上传一个分块
        fileName,
        PartUploadFileInfo(
          partNumber: k + 1,
          uploadId: uploadId!,
          fileBytes: chunk,
        ),
        storageServiceSetting,
      );
      //任务完成后将结果添加到列表并标记为已完成
      task.then((result) {
        chunkResults.add(result);
        concurrentCount--;
        hasUploadNumber++;
        controller.state.uploadProgress = hasUploadNumber / totlePerBatch;
        completer.complete(result);
      });
      tasks.add(completer.future);
      concurrentCount++;
      // 控制上传并发数
      while (concurrentCount >= 3) {
        await Future.delayed(Duration(seconds: 1));
      }
    }
    //等待所有上传任务完成
    await Future.wait(tasks);
    chunkResults.sort((a, b) => a.partNumber.compareTo(b.partNumber));
    return chunkResults;
  }

  Future<List<String>> _uploadLargeFile(
    Uint8List fileBytes,
    String fileName,
  ) async {
    final chunks = _splitFileIntoChunks(fileBytes); //将文件分割成多个分块
    final totalChunkCount = chunks.length;
    final chunkCountPerBatch = maxChunkCountPerBatch;

    final batchCount = totalChunkCount ~/ chunkCountPerBatch +
        (totalChunkCount % chunkCountPerBatch == 0 ? 0 : 1);
    final List<String> resultUrlList = [];
    //计算需要分批上传的批数

    for (int i = 0; i < batchCount; i++) {
      //循环上传每个批次的数据
      final startIndex = i * chunkCountPerBatch;
      var partFileName =
          fileName.split('.')[0] + i.toString() + fileName.split('.')[1];
      final endIndex = (startIndex + chunkCountPerBatch) < totalChunkCount
          ? (startIndex + chunkCountPerBatch)
          : totalChunkCount;
      final chunkBatch = chunks.sublist(startIndex, endIndex);

      final chunkBatchFutures = await _uploadChunks(
        chunkBatch,
        partFileName,
        startIndex,
      ); //上传多个分块
      final resultUrl = await _mergeChunksIntoSingleFile(
        partFileName,
        chunkBatchFutures,
      );
      //合并分块
      resultUrlList.add(resultUrl);
    }
    return resultUrlList;
  }

  /// 小于200m的文件
  Future<List<String>> _uploadSmallFile(
    Uint8List fileBytes,
    String fileName,
  ) async {
    final chunks = _splitFileIntoChunks(fileBytes); //将文件分割成多个分块
    final chunkResults = await _uploadChunks(chunks, fileName); //上传多个分块
    final resultUrl = await _mergeChunksIntoSingleFile(
      fileName,
      chunkResults,
    ); //合并分块
    return [resultUrl];
  }
}
