import 'package:flyinsono/lab/manager/interfaces/measure.dart';
import 'package:flyinsono/lab/mock_data/mock_rpc.dart';
import 'package:flyinsono/lab/pages/lab_image/urm_data_processor/urm_params.dart';
import 'package:flyinsono/lab/pages/lab_image/widgets/image_operate_panel/controller.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:flyinsono/rpc.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_measure/interfaces/process/items/item_metas.dart';
import 'package:fis_measure/interfaces/process/items/terms.dart';
import 'package:fis_measure/process/items/item_meta_convert.dart';
import 'package:get/get.dart';
import 'package:fis_measure/view/measure/measure_config/measure_configuation_page.dart';
import 'base_manager.dart';
import 'package:fis_jsonrpc/rpc.dart' hide DRect;
import 'package:flyinsono/lab/pages/lab_image/widgets/image_measure_overlay/widgets/rim_measure_result_table.dart';
import 'dart:async';
import 'package:fis_measure/process/workspace/urm/application.dart';
import 'dart:math' as math;
import 'package:fis_measure/interfaces/process/items/types.dart';
import 'package:fis_i18n/i18n.dart';

class MeasureManager extends BaseManager implements IMeasureManager {
  @override
  Future<MeasureApplicationDTO?> getMeasureApplicationAsync({
    required MeasureModeSelection measureModeSelection,
  }) async {
    try {
      return await rpc.remedical.getMeasureApplicationAsync(
        GetMeasureApplicationRequest(
          token: token,
          applicationName: measureModeSelection.applicationName,
          categoryName: measureModeSelection.categoryName,
          measureModes: measureModeSelection.measureModes,
          // projectCode: measureModeSelection.projectCode,
        ),
      );
    } catch (e) {
      logger.e('Project getMeasureApplicationAsync ex:', e);

      return null;
    }
  }

  @override
  List<MeasureItemInfo> getMeasureItems({
    required List<MeasureModeDTO> measureModeList,
    required String modeName,
    required bool isUrmMrasure,
  }) {
    List<ItemMeta> itemMetas = [];
    List<MeasureItemInfo> measureItems = [];

    ///群组列表
    var groups = measureModeList
        .firstWhereOrNull(
          (element) => element.modeName == modeName,
        )
        ?.availableGroups;
    if (groups != null && groups.isNotEmpty) {
      ///项目列表
      var folders = groups[0].availableFolders;
      if (folders != null && folders.isNotEmpty) {
        if (folders[0].availableItems != null) {
          var workingItemNames = folders.first.workingItemNames;

          itemMetas = folders[0]
              .availableItems!
              // 排除不支持的测量项
              .where((item) =>
                  !MeasureUnsupportedTerms.items.contains(item.description))
              .where((item) =>
                  workingItemNames?.contains(item.description) ?? false)
              .map((item) {
                try {
                  return ItemMetaConverter(item).output();
                } catch (e) {
                  print(
                      "Item meta -[${item.description}] convert error; JSON-Text: ${item.toJson()}");
                  logger.e(
                    "Item meta -[${item.description}] convert error; JSON-Text: ${item.toJson()}",
                    e,
                  );
                  return null;
                }
              })
              .where((item) => item != null)
              .map((e) => e!)
              .toList();
          itemMetas.forEach((item) {
            measureItems.add(
              MeasureItemInfo(
                itemMeta: item,
                description: item.description,
              ),
            );
          });
        }
      }
    }
    return measureItems;
  }

  @override
  List<String> chooseMeasureList(
      {required List<MeasureModeDTO> measureModeList,
      required String modeName}) {
    List<String> list = [];

    ///群组列表
    var groups = measureModeList
        .firstWhereOrNull(
          (element) => element.modeName == modeName,
        )
        ?.availableGroups;
    if (groups != null && groups.isNotEmpty) {
      ///项目列表
      var folders = groups[0].availableFolders;
      if (folders != null && folders.isNotEmpty) {
        if (folders[0].availableItems != null) {
          var workingItemNames = folders.first.workingItemNames;

          list = workingItemNames ?? [];
        }
      }
    }
    return list;
  }

  @override
  List<URMMeasureItem> getURMMeasureItems({
    required List<MeasureModeDTO> measureModeList,
  }) {
    List<URMMeasureItem> itemMetas = [];

    ///群组列表
    var groups = measureModeList
        .firstWhereOrNull(
          (element) => element.modeName == "URM",
        )
        ?.availableGroups;
    if (groups != null && groups.isNotEmpty) {
      ///项目列表
      List<MeasureFolderDTO> folders = groups[0].availableFolders ?? [];
      if (folders.isNotEmpty) {
        for (MeasureFolderDTO i in folders) {
          itemMetas.add(URMMeasureItem(
            urmMeasureItems: urmMeasureItems(i.availableItems, i),
            urmName: i.name!,
          ));
        }
      }
    }
    return itemMetas;
  }

  List<MeasureItemInfo> urmMeasureItems(
      List<ItemMetaDTO>? availableItems, MeasureFolderDTO measureFolder) {
    List<ItemMeta> itemMetas = [];
    List<MeasureItemInfo> measureItems = [];
    if (availableItems != null) {
      List<String> workingItemNames = measureFolder.workingItemNames ?? [];

      itemMetas = availableItems
          // 排除不支持的测量项
          .where((item) =>
              !MeasureUnsupportedTerms.items.contains(item.description))
          .where((item) => workingItemNames.contains(item.description))
          .map((item) {
            try {
              return ItemMetaConverter(item).output();
            } catch (e) {
              print(
                  "Item meta -[${item.description}] convert error; JSON-Text: ${item.toJson()}");
              logger.e(
                "Item meta -[${item.description}] convert error; JSON-Text: ${item.toJson()}",
                e,
              );
              return null;
            }
          })
          .where((item) => item != null)
          .map((e) => e!)
          .toList();

      for (String j in workingItemNames) {
        for (ItemMeta i in itemMetas) {
          if (i.description == j) {
            measureItems.add(
              MeasureItemInfo(
                itemMeta: i,
                description: i.description,
              ),
            );
          }
        }
      }
    }
    return measureItems;
  }

  @override
  MeasureConfigItem measureConfig({
    required List<MeasureModeDTO> availableModes,
    required List<MeasureItemCategory> measureItemCategories,
    required int selectedCategoryIndex,
  }) {
    List<ItemMetaGroup> _itemMetaConfigurationList = [];
    Map<String, List<ItemMetaDTO>> _group = {};
    List<String> chooseMeasure = [];
    if (measureItemCategories[selectedCategoryIndex].typeName == null) {
      /// 获取urm配置
      getURMMeasureConfigurationGroupName().forEach(
        ((element) {
          var groups = availableModes
              .firstWhereOrNull((element) => element.modeName == "URM")
              ?.availableGroups;

          for (MeasureFolderDTO i in groups?.first.availableFolders ?? []) {
            if (i.name ==
                measureItemCategories[selectedCategoryIndex].categoryName) {
              chooseMeasure = i.workingItemNames ?? [];
              List<ItemMetaDTO> itemMetaListGroupItem = [];

              for (ItemMetaDTO j in i.availableItems ?? []) {
                if (j.categories
                        ?.toList()
                        .contains(element.itemMetaGroupTitle) ??
                    false) {
                  if (!MeasureUnsupportedTerms.items.contains(j.name)) {
                    itemMetaListGroupItem.add(j);
                  }
                }
              }
              _group[element.itemMetaGroupTitle] = itemMetaListGroupItem;
            }
          }
        }),
      );
      _group.forEach(
        (key, value) {
          if (key == 'Common') {
            _itemMetaConfigurationList.add(
              ItemMetaGroup(key, value, true),
            );
          } else {
            _itemMetaConfigurationList.add(
              ItemMetaGroup(key, value, false),
            );
          }
        },
      );
      return MeasureConfigItem(
        chooseMeasure: chooseMeasure,
        itemMetaListGroup: _itemMetaConfigurationList,
      );
    } else {
      getMeasureConfigurationGroupName().forEach(
        ((element) {
          List<ItemMetaDTO> itemMetaListGroupItem = [];
          var groups = availableModes
              .firstWhereOrNull((element) =>
                  element.modeName ==
                  measureItemCategories[selectedCategoryIndex].typeName)
              ?.availableGroups;

          (groups?[0].availableFolders![0].availableItems)?.toList().forEach(
            (e) {
              if (e.categories?.toList().contains(element.itemMetaGroupTitle) ??
                  false) {
                if (!MeasureUnsupportedTerms.items.contains(e.name)) {
                  itemMetaListGroupItem.add(e);
                }
              }
              _group[element.itemMetaGroupTitle] = itemMetaListGroupItem;
            },
          );
        }),
      );
      _group.forEach(
        (key, value) {
          if (key == 'Common') {
            _itemMetaConfigurationList.add(
              ItemMetaGroup(key, value, true),
            );
          } else {
            _itemMetaConfigurationList.add(
              ItemMetaGroup(key, value, false),
            );
          }
        },
      );
    }

    return MeasureConfigItem(
      chooseMeasure: chooseMeasureList(
        measureModeList: availableModes,
        modeName: measureItemCategories[selectedCategoryIndex].typeName ?? '',
      ),
      itemMetaListGroup: _itemMetaConfigurationList,
    );
  }

  @override
  List<ItemMetaDTO> setMeasureConfigItemMetaList({
    required List<MeasureModeDTO> availableModes,
    required List<MeasureItemCategory> measureItemCategories,
    required int selectedCategoryIndex,
  }) {
    List<ItemMetaDTO> _measureConfigItemMetaList = [];

    if (measureItemCategories[selectedCategoryIndex].typeName == null) {
      var groups = availableModes
          .firstWhereOrNull((element) => element.modeName == "URM")
          ?.availableGroups;

      for (MeasureFolderDTO i in groups?.first.availableFolders ?? []) {
        if (i.name ==
            measureItemCategories[selectedCategoryIndex].categoryName) {
          for (ItemMetaDTO j in i.availableItems ?? []) {
            if (!MeasureUnsupportedTerms.items.contains(j.name)) {
              _measureConfigItemMetaList.add(j);
            }
          }
        }
      }
    } else {
      var groups = availableModes
          .firstWhereOrNull((element) =>
              element.modeName ==
              measureItemCategories[selectedCategoryIndex].typeName)
          ?.availableGroups;
      (groups![0].availableFolders![0].availableItems)?.toList().forEach(
        (e) {
          if (!MeasureUnsupportedTerms.items.contains(e.name)) {
            _measureConfigItemMetaList.add(e);
          }
        },
      );
    }

    return _measureConfigItemMetaList;
  }

  /// 跟超声机端保持一致，配置 项目写死
  List<ItemMetaGroup> getMeasureConfigurationGroupName() {
    return [
      ItemMetaGroup('Common', [], true),
      ItemMetaGroup('ABD', [], false),
      ItemMetaGroup('CARD', [], false),
      ItemMetaGroup('GYN', [], false),
      ItemMetaGroup('OB', [], false),
      ItemMetaGroup('VAS', [], false),
      ItemMetaGroup('VET', [], false),
    ];
  }

  /// URM 特殊处理
  List<ItemMetaGroup> getURMMeasureConfigurationGroupName() {
    return [
      ItemMetaGroup('Common', [], true),
      ItemMetaGroup('ABD', [], false),
      ItemMetaGroup('CARD', [], false),
      ItemMetaGroup('GYN', [], false),
      ItemMetaGroup('OB', [], false),
      ItemMetaGroup('VAS', [], false),
    ];
  }

  @override
  Future<URMColorbarResult?> getURMColorbar({
    required int processType,
    PostProcessImageParams? postProcessImageParams,
    ProcessPosParams? processPosParams,
    String? remedicalCode,
    List<UrmPoint>? urmTraceDPoints,
    String? urmImageType,
    int? urmBlend,
    int? imgProcessVer,
    bool? zoomOn,
  }) async {
    try {
      URMColorbarResult result = await rpc.aIDiagnosis.getURMColorbarAsync(
        URMColorbarRequest(
          token: token,
          processType: processType,
          downsampleIndex: postProcessImageParams?.downsampleIndex ?? 0,
          intPowerDen: postProcessImageParams?.intPowerDen ?? 0,
          intPowerDir: postProcessImageParams?.intPowerDir ?? 0,
          sigmaGauss: postProcessImageParams?.sigmaGauss ?? 0,
          vessScale: postProcessImageParams?.vessScale ?? 0,
          velMaxScaler: postProcessImageParams?.velMaxScaler ?? 0,
          velMinScaler: postProcessImageParams?.velMinScaler ?? 0,
          iterations: postProcessImageParams?.iterations ?? 0,
          zoomRoix: processPosParams?.zoomRoiX ?? 0,
          zoomRoiy: processPosParams?.zoomRoiY ?? 0,
          zoomRoiwidth: processPosParams?.zoomRoiW ?? 0,
          zoomRoiheight: processPosParams?.zoomRoiH ?? 0,
          roix: processPosParams?.roiX ?? 0,
          roiy: processPosParams?.roiY ?? 0,
          roiwidth: processPosParams?.roiW ?? 0,
          roiheight: processPosParams?.roiH ?? 0,
          screenWidth: processPosParams?.screenW ?? 0,
          screenHeight: processPosParams?.screenH ?? 0,
          remedicalCode: remedicalCode,
          urmTraceDPoints: urmTraceDPoints,
          urmImageType: urmImageType,
          urmBlend: urmBlend ?? 0,
          imgProcessVer: imgProcessVer ?? 0,
          zoomOn: zoomOn ?? false,
        ),
      );
      return result;
    } catch (e) {
      logger.e('Project getMeasureApplicationAsync ex:', e);

      return null;
    }
  }

  @override
  List<RimMeasureRowResult> handleMesureresult(
      {URMRimMesureResult? mesureresult}) {
    URMMeasureProcessResult? rimResult = mesureresult!.result;
    if (rimResult == null) return [];
    List<RimMeasureRowResult> rimMeasureResultList = [];
    URMDenMeasureResult? denMeasureResult = rimResult.denMeasureResult;
    URMVelMeasureResult? velMeasureResult = rimResult.velMeasureResult;
    if (denMeasureResult == null || velMeasureResult == null) return [];
    if (mesureresult.measureType == MeasureTypes.URMShellDenMeasure ||
        mesureresult.measureType == MeasureTypes.URMShellDenVelMeasure) {
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMDenROI + "(%)",
        rim: denMeasureResult.roiDen * 100,
        inRim: denMeasureResult.inRoiDen * 100,
        outRim: denMeasureResult.outRoiDen * 100,
        unit: Unit.percent,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMDenFractalDim,
        rim: denMeasureResult.roiFractalDim,
        inRim: denMeasureResult.inRoiFractalDim,
        outRim: denMeasureResult.outRoiFractalDim,
        unit: Unit.None,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMDenMax,
        rim: denMeasureResult.maxDensity,
        inRim: denMeasureResult.inMaxDensity,
        outRim: denMeasureResult.outMaxDensity,
        unit: Unit.None,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMDenMin,
        rim: denMeasureResult.minDensity,
        inRim: denMeasureResult.inMinDensity,
        outRim: denMeasureResult.outMinDensity,
        unit: Unit.None,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMDenMean,
        rim: denMeasureResult.meanDensity,
        inRim: denMeasureResult.inMeanDensity,
        outRim: denMeasureResult.outMeanDensity,
        unit: Unit.None,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMDenStd,
        rim: math.sqrt(denMeasureResult.varianceDensity),
        inRim: math.sqrt(denMeasureResult.inVarianceDensity),
        outRim: math.sqrt(denMeasureResult.outVarianceDensity),
        unit: Unit.None,
      ));
    }

    if (mesureresult.measureType == MeasureTypes.URMShellVelMeasure ||
        mesureresult.measureType == MeasureTypes.URMShellDenVelMeasure) {
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMVelMax + '(mm/s)',
        rim: velMeasureResult.maxVel,
        inRim: velMeasureResult.inMaxVel,
        outRim: velMeasureResult.outMaxVel,
        unit: Unit.mms,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMVelMin + '(mm/s)',
        rim: velMeasureResult.minVel,
        inRim: velMeasureResult.inMinVel,
        outRim: velMeasureResult.outMinVel,
        unit: Unit.mms,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMVelMean + '(mm/s)',
        rim: velMeasureResult.meanVel,
        inRim: velMeasureResult.inMeanVel,
        outRim: velMeasureResult.outMeanVel,
        unit: Unit.mms,
      ));
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.URMVelStd + '(mm/s)',
        rim: math.sqrt(velMeasureResult.varianceVel),
        inRim: math.sqrt(velMeasureResult.inVarianceVel),
        outRim: math.sqrt(velMeasureResult.outVarianceVel),
        unit: Unit.None,
      ));
    }
    if (mesureresult.measureType == MeasureTypes.URMShellVelMeasure) {
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.Area + '(cm²)',
        rim: velMeasureResult.roiArea,
        inRim: velMeasureResult.inRoiArea,
        outRim: velMeasureResult.outRoiArea,
        unit: Unit.cm2,
      ));
    } else if (mesureresult.measureType == MeasureTypes.URMShellDenMeasure) {
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.Area + '(cm²)',
        rim: denMeasureResult.roiArea,
        inRim: denMeasureResult.inRoiArea,
        outRim: denMeasureResult.outRoiArea,
        unit: Unit.cm2,
      ));
    } else {
      rimMeasureResultList.add(RimMeasureRowResult(
        rowName: MeasureTerms.Area + '(cm²)',
        rim: denMeasureResult.roiArea,
        inRim: denMeasureResult.inRoiArea,
        outRim: denMeasureResult.outRoiArea,
        unit: Unit.cm2,
      ));
    }

    return rimMeasureResultList;
  }

  /// 获取注释
  @override
  Future<CommentItemResultDTO?> getCommentsByApplicationAsync(
    String applicationName,
    String categoryName,
  ) async {
    try {
      final result = await rpc.remedical.getCommentsByApplicationAsync(
        GetCommentsByApplicationRequest(
          token: token,
          applicationName: applicationName,
          categoryName: categoryName,
          languageCode: i18nBook.locale.toCodeString('-'),
        ),
      );
      return result;
    } catch (e) {
      logger.e('MeasureHomeController getCommentsByApplicationAsync ex: ', e);
      return null;
    }
  }

  @override
  Future<BodyPatternsResult?> getBodyPatternsByApplication({
    String? applicationName,
    String? categoryName,
    String languageCode = 'zh-CN',
  }) async {
    try {
      BodyPatternsResult result =
          await rpc.remedical.getBodyPatternsByApplicationAsync(
        GetBodyPatternByApplicationRequest(
          token: token,
          languageCode: languageCode,
          applicationName: applicationName,
          categoryName: categoryName,
        ),
      );
      return result;
    } catch (e) {
      logger.e('getBodyPatternsByApplication ex: ', e);
      return null;
    }
  }

  @override
  Future<bool> saveUserDefinedBodyPattern({
    required String applicationName,
    required String categoryName,
    String? category,
    String? description,
    List<String> imageUrlList = const [],
  }) async {
    try {
      List<BodyPatternDTO> bodyPatternItems = [];
      bodyPatternItems.add(BodyPatternDTO(
        category: category,
        description: description,
        imageUrlList: imageUrlList,
      ));
      bool result = await rpc.remedical.saveUserDefinedBodyPatternAsync(
        SaveUserDefinedBodyPatternsRequest(
          token: token,
          applicationName: applicationName,
          categoryName: categoryName,
          bodyPatternItems: bodyPatternItems,
        ),
      );
      return result;
    } catch (e) {
      logger.e("saveUserDefinedBodyPattern ex:", e);
      return false;
    }
  }

  @override
  Future<bool> resetUserBodyPatterns({
    required String applicationName,
    required String categoryName,
    bool isAllReset = false,
  }) async {
    try {
      bool result = await rpc.remedical.resetUserBodyPatternsAsync(
        ResetUserBodyPatternsRequest(
          token: token,
          applicationName: applicationName,
          categoryName: categoryName,
          isAllReset: isAllReset,
        ),
      );
      return result;
    } catch (e) {
      logger.e("resetUserBodyPatterns ex:", e);
      return false;
    }
  }
}
