import 'dart:convert';

import 'package:file_picker/file_picker.dart';
import 'package:fis_common/index.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_theme/theme.dart';
import 'package:fis_ui/base_define/page.dart';
import 'package:fis_ui/index.dart';
import 'package:fis_ui/interface/interactive_container.dart';
import 'package:fis_ui/values/font_sizes.dart';
import 'package:fis_ui/widgets/progressbar/progressbar.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flyinsono/architecture/define.dart';
import 'package:flyinsono/architecture/router/index.dart';
import 'package:flyinsono/rpc.dart';
import 'package:flyinsono/views/desktop/laboratory/controller.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:universal_html/html.dart';

class UploadCasesDialog extends FStatefulWidget implements FPage {
  const UploadCasesDialog({super.key});

  @override
  FState<UploadCasesDialog> createState() => _UploadCasesDialogState();

  @override
  String get pageName => 'UploadCasesDialog';
}

class _UploadCasesDialogState extends FState<UploadCasesDialog> {
  final controller = Get.find<LaboratoryController>();

  bool _uploading = false;
  double _uploadProgress = 0.0;
  int _totalFileSize = 0;
  int _totalUploadedFileSize = 0;
  bool _cancelFlag = false;
  final int chunkSize = 5 * 1024 * 1024;

  @override
  void initState() {
    super.initState();
  }

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

  @override
  FWidget build(BuildContext context) {
    return FSimpleDialog(
      title: FText(
        _uploading
            ? i18nBook.laboratory.uploadProgress.t
            : i18nBook.laboratory.uploadOptions.t,
        style: TextStyle(
          color: Colors.white,
        ),
      ),
      okString: i18nBook.common.confirm.t,
      cancelString: i18nBook.common.cancel.t,
      isDefault: false,
      bottomButton: _buildBottomButton(),
      onClose: () => _onCancel(),
      children: [
        FContainer(
          width: 500,
          alignment: Alignment.centerLeft,
          padding: EdgeInsets.symmetric(vertical: 20),
          child: _uploading ? _buildUploadProgress() : _buildUploadCases(),
        ),
      ],
    );
  }

  FWidget _buildUploadCases() {
    return FColumn(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        _buildUploadOptionsItem(
          title: i18nBook.laboratory.uploadMethod.t,
          optionItem: _buildOptionValueItem(
            _buildUploadMethod(),
            isSelect: true,
          ),
        ),
        FObx(() {
          if (controller.state.currentUploadMethod ==
              LabUploadTypeEnum.ByTemplate)
            return FContainer(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.only(right: 25),
              child: FText.rich(
                TextSpan(
                  text: i18nBook.laboratory.downloadTemplate.t,
                  style: TextStyle(
                    fontFamily: FTheme.ins.localeSetting.fontFamily,
                    color: FTheme.ins.colorScheme.primary,
                  ),
                  recognizer: TapGestureRecognizer()
                    ..onTap = () async {
                      _downloadFileFromWeb();
                    },
                ),
              ),
            );
          else
            return FSizedBox();
        }),
        _buildUploadOptionsItem(
          title: i18nBook.laboratory.comprehensiveImageAnalysis.t,
          optionItem: FObx(
            () => _buildAnalysisSwitch(
              switchValue: controller.state.currentComprehensiveImageAnalysis,
              onValueChange: (value) {
                controller.state.currentComprehensiveImageAnalysis = value;
              },
            ),
          ),
        ),
        _buildUploadOptionsItem(
          title: i18nBook.laboratory.imagesAnalyzedIndividually.t,
          optionItem: FObx(
            () => _buildAnalysisSwitch(
              switchValue: controller.state.currentImageAnalysisAlone,
              onValueChange: (value) {
                controller.state.currentImageAnalysisAlone = value;
              },
            ),
          ),
        ),
        if (controller.state.selectedKey.isEmpty)
          _buildUploadOptionsItem(
            title: i18nBook.laboratory.imageFolderName.t,
            isRequired: true,
            optionItem: _buildOptionValueItem(
              _buildShordCodeInput(),
            ),
          ),
      ],
    );
  }

  FWidget _buildOptionValueItem(
    FWidget optionItem, {
    bool isSwitch = false,
    bool isSelect = false,
  }) {
    return FContainer(
      height: 38,
      padding: isSwitch ? EdgeInsets.zero : EdgeInsets.only(left: 10),
      child: FRow(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          isSelect
              ? FExpanded(
                  child: optionItem,
                )
              : optionItem,
        ],
      ),
    );
  }

  FWidget _buildAnalysisSwitch({
    required bool switchValue,
    required ValueCallback onValueChange,
  }) {
    return _buildOptionValueItem(
      FSwitch(
        value: switchValue,
        onChanged: (value) => onValueChange(value),
      ),
      isSwitch: true,
    );
  }

  /// 单个上传选项
  FWidget _buildUploadOptionsItem({
    required String title,
    required FWidget optionItem,
    bool? isRequired = false,
  }) {
    return FContainer(
      alignment: Alignment.centerLeft,
      padding: EdgeInsets.symmetric(horizontal: 25, vertical: 5),
      child: FRow(
        children: [
          FContainer(
            width: 150,
            child: FText.rich(
              TextSpan(
                children: [
                  TextSpan(
                    text: title,
                    style: TextStyle(
                      fontSize: FFontSizes.H6,
                    ),
                  ),
                  if (isRequired!)
                    TextSpan(
                      text: '*',
                      style: TextStyle(
                        fontSize: FFontSizes.H6,
                        color: Colors.red,
                      ),
                    ),
                ],
              ),
            ),
          ),
          FExpanded(
            child: optionItem,
          ),
        ],
      ),
    );
  }

  FWidget _buildUploadMethod() {
    List<FSelectOptionModel> selectList = [
      FSelectOptionModel(
        title: i18nBook.laboratory.directUpload.t,
        value: LabUploadTypeEnum.DirectUpload.index.toString(),
      ),
      FSelectOptionModel(
        title: i18nBook.laboratory.uploadByTemplate.t,
        value: LabUploadTypeEnum.ByTemplate.index.toString(),
      ),
    ];

    final select = FObx(
      () => FSelect<FSelectOptionModel, String>(
        source: selectList,
        fontFamily: FTheme.ins.localeSetting.fontFamily,
        value: controller.state.currentUploadMethod.index.toString(),
        height: 36,
        optionLabelExtractor: (data) => data.title,
        optionValueExtractor: (data) => data.value,
        onSelectChanged: (value, index) {
          controller.state.currentUploadMethod =
              LabUploadTypeEnum.values[int.parse(value ?? '0')];
        },
      ),
    );

    return select;
  }

  // 文件夹名称
  FWidget _buildShordCodeInput() {
    return FBorderInput(
      hintSize: 16,
      contentSize: 16,
      maxLength: 20,
      borderColor: Color.fromRGBO(234, 234, 234, 1),
      height: 38,
      hintText: i18nBook.laboratory.pleaseEnterFolderImageName.t,
      onChanged: (value) {
        controller.state.currentImageFolderName = value;
      },
    );
  }

  FWidget _buildUploadProgress() {
    return FContainer(
      padding: EdgeInsets.symmetric(horizontal: 15),
      child: FColumn(
        children: [
          FSizedBox(height: 8.0),
          FProgeressbar(
            percentage: _uploadProgress,
            lineHeight: 20,
            animation: true,
            animationDuration: 100,
            animateFromLastPercentage: true,
            alignment: MainAxisAlignment.spaceBetween,
            child: FText(
              _getProgressDisplay(_uploadProgress),
              textAlign: TextAlign.center,
              style: TextStyle(fontSize: 16, color: Colors.white),
            ),
            backgroundColor: Colors.black26,
            progressBarColor: Colors.blue,
          ),
          FSizedBox(height: 8.0),
        ],
      ),
    );
  }

  void _showConfirmDialog(FInteractiveContainer businessParent) {
    FConfirmAlert.show(
      context: Get.context!,
      businessParent: businessParent,
      title: i18nBook.common.tip.t,
      subTitle: i18nBook.laboratory.confirmCancellationUploadOperation.t,
      confrimLabel: i18nBook.common.confirm.t,
      cancelLabel: i18nBook.common.cancel.t,
      onConfirm: () async {
        Get.back();
        setState(() {
          _cancelFlag = true;
        });
      },
    );
  }

  ///底部操作按钮
  FWidget _buildBottomButton() {
    return FContainer(
      alignment: Alignment.center,
      padding: EdgeInsets.symmetric(vertical: 15),
      child: FFlex(
        direction: Axis.horizontal,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        mainAxisSize: MainAxisSize.min,
        children: [
          if (!_uploading) ...[
            FElevatedButton(
              businessParent: this.widget,
              name: "upload",
              onPressed: () {
                _uploadFiles();
              },
              style: ButtonStyle(
                padding: MaterialStateProperty.all(
                  EdgeInsets.symmetric(
                    vertical: 15,
                    horizontal: 25,
                  ),
                ),
              ),
              child: FText(i18nBook.common.confirm.t),
            ),
            FSizedBox(
              width: 20,
            ),
          ],
          FOutlinedButton(
            name: "cancel",
            businessParent: this.widget,
            onPressed: () => _onCancel(),
            style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(
                Colors.white,
              ),
              padding: MaterialStateProperty.all(
                EdgeInsets.symmetric(vertical: 15, horizontal: 25),
              ),
            ),
            child: FText(
              i18nBook.common.cancel.t,
              style: TextStyle(
                color: FTheme.ins.data.colorScheme.primary,
              ),
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _downloadFileFromWeb() async {
    final response =
        await http.get(Uri.parse(controller.state.templateFileUrl));
    final bytes = response.bodyBytes;
    bool isShell = FPlatform.isMacOS || FPlatform.isWindows;
    if (isShell) {
      var data = base64Encode(bytes);
      await rpc.platform.setBytesToExport(data, '模板.zip');
      return;
    }
    final blob = Blob([bytes], 'application/zip');
    final link = AnchorElement(href: Url.createObjectUrlFromBlob(blob));
    link.download = '模板.zip';
    link.click();
  }

  String _getProgressDisplay(double exportState) {
    if (_uploadProgress == 1.0) {
      return "100%";
    }
    return (_uploadProgress * 100).toStringAsPrecision(2) + "%";
  }

  // 设置上传状态的回调函数，更新已上传文件大小的总和和上传进度
  void _updateUploadProgress(
    int uploadedFileSize,
  ) {
    try {
      setState(() {
        _totalUploadedFileSize++;
        _uploadProgress =
            _totalUploadedFileSize.toDouble() / _totalFileSize.toDouble();
      });
    } catch (e) {}
  }

  // 取消
  void _onCancel() {
    if (_uploading) {
      _showConfirmDialog(this.widget);
    } else {
      router.back();
    }
  }

// 上传单个分片的函数，传入分片、文件名、分片序号和总分片数，返回上传结果
  // Future<String> _uploadChunk(
  //   Uint8List chunk,
  //   String fileName,
  //   int chunkIndex,
  //   int chunkCount,
  // ) async {
  //   String uploadResult =
  //       await rpc.storage.uploadUint8List(chunk, fileName) ?? '';
  //   // 设置上传状态的回调函数，更新已上传文件大小的总和和上传进度
  //   _updateUploadProgress(
  //     chunkIndex,
  //   );
  //   return uploadResult;
  // }

// 上传整个文件
  Future<String> _uploadWholeFile(
    Uint8List fileBytes,
    String fileName,
  ) async {
    String uploadResult =
        await rpc.storage.uploadUint8List(fileBytes, fileName) ?? '';
    // 设置上传状态的回调函数，更新已上传文件大小的总和和上传进度
    _updateUploadProgress(
      fileBytes.length,
    );
    return uploadResult;
  }

  // 计算上传文件需要上传的总次数
  int _getUploadTimes(List<PlatformFile> files) {
    int totalTimes = 0;
    for (PlatformFile file in files) {
      int fileSize = file.size;
      int chunkCount =
          fileSize ~/ chunkSize + (fileSize % chunkSize == 0 ? 0 : 1);
      totalTimes += chunkCount;
    }
    return totalTimes;
  }

  // 上传文件的函数
  Future<void> _uploadFiles() async {
    if (controller.validateRequiredFields()) {
      final result = await FilePicker.platform.pickFiles(
        type: FileType.custom,
        allowMultiple: true,
        allowedExtensions: ['jpg', 'png', 'mp4', 'dicom', 'zip'],
      );
      setState(() {
        _uploading = true;
        _uploadProgress = 0.0;
        _totalUploadedFileSize = 0;
        _totalFileSize = 0;
      });

      if (result == null || result.files.isEmpty) {
        setState(() {
          _uploading = false;
        });
        return;
      }

      List<FileUploadInfoDTO> fileUploadInfos = [];
      _totalFileSize = _getUploadTimes(result.files);
      for (int i = 0; i < result.files.length; i++) {
        final fileName = result.files[i].name;
        final fileBytes = result.files[i].bytes!;
        final fileSize = fileBytes.length;

        if (fileSize <= chunkSize) {
          if (_cancelFlag) {
            return;
          }
          // 如果文件大小小于等于分片大小，则直接上传整个文件
          String uploadResult = await _uploadWholeFile(
            fileBytes,
            fileName,
          );
          fileUploadInfos.add(FileUploadInfoDTO(
            uploadId: fileName.split('.')[0],
            partNum: 0,
            fileUrl: uploadResult,
            fileName: fileName,
          ));
        } else {
          // 如果文件大小大于分片大小，则进行分片上传
          // 这边初始化生成一个uploadId
          String? uploadId =
              await rpc.storage.initiateMultipartUploadResult(fileName);
          List<Uint8List> chunks = [];
          int chunkCount =
              fileSize ~/ chunkSize + (fileSize % chunkSize == 0 ? 0 : 1);
          for (int j = 0; j < chunkCount; j++) {
            Uint8List chunk = fileBytes.sublist(
                j * chunkSize,
                (j + 1) * chunkSize < fileSize
                    ? (j + 1) * chunkSize
                    : fileSize);
            chunks.add(chunk);
          }
          List<PartFileResultInfo> chunkResults = [];
          String resultUrl = '';
          StorageServiceSettingDTO storageServiceSetting =
              StorageServiceSettingDTO();
          for (int k = 0; k < chunkCount; k++) {
            Uint8List chunk = chunks[k];
            if (_cancelFlag) {
              return;
            }
            if (k == 0) {
              storageServiceSetting = await rpc.storage.multiPartUploadGetAuth(
                fileName,
                PartUploadFileInfo(
                  partNumber: k + 1,
                  uploadId: uploadId ?? '',
                  fileBytes: chunk,
                ),
              );
            }
            PartFileResultInfo? partFileResultInfo =
                await rpc.storage.multiPartUploadAsync(
              fileName,
              PartUploadFileInfo(
                partNumber: k + 1,
                uploadId: uploadId ?? '',
                fileBytes: chunk,
              ),
              storageServiceSetting,
            );

            // 将分块文件名的中间部分改为坐标，从0开始递增
            chunkResults.add(partFileResultInfo);
          }
          resultUrl = await rpc.storage.completeMulitPartUploadFileAsync(
              fileName, uploadId ?? '', chunkResults);
          fileUploadInfos.add(FileUploadInfoDTO(
            uploadId: fileName.split('.')[0],
            partNum: 0,
            fileUrl: resultUrl,
            fileName: fileName,
          ));
        }

        controller.state.fileUploadInfos = fileUploadInfos;
      }

      controller.recordLaboratoryFile();
    }
  }
}
