import 'dart:convert';
import 'package:fis_measure/process/workspace/rpc_bridge.dart';
import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_lib_pdf/pdf_helper.dart';
import 'package:fis_lib_report/report/report_template_document.dart';
import 'package:fis_lib_report/report_info/report_info.dart' as report;
import 'package:fis_measure/utils/prompt_box.dart';
import 'package:fis_ui/index.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sms/flutter_sms.dart';
import 'package:fluwx/fluwx.dart';
import 'package:flyinsono/architecture/define.dart';
import 'package:flyinsono/architecture/router/desktop/names.dart';
import 'package:flyinsono/architecture/router/router.dart';
import 'package:flyinsono/architecture/services/entity/local_setting.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/architecture/storage/file_storage.dart';
import 'package:flyinsono/global.dart';
import 'package:flyinsono/managers/base_manager.dart';
import 'package:flyinsono/managers/interfaces/entities/reportEditSource.dart';
import 'package:flyinsono/pages/main/home/controller.dart';
import 'package:flyinsono/pages/main/profile_complete/widgets/row_separator.dart';
import 'package:flyinsono/pages/remedical/consultation/widgets/report/report_share_dialog.dart';
import 'package:flyinsono/pages/remedical/report/report_edit/entitys/report_tag_key.dart';
import 'package:flyinsono/pages/remedical/report_preview/controller.dart';
import 'package:flyinsono/rpc.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher.dart';
import 'interfaces/entities/report_element_info.dart';
import 'interfaces/report.dart';
import 'package:fis_common/event/event_type.dart';

class ReportManager extends BaseManager implements IReportManager {
  final fileStorage = FileStorage.createInstance("remedical/report");
  final onEditReport = FEventHandler<String>();
  ReportDataPipe get reportDataPipe => ReportDataPipe(
      cacheGet: fileStorage.getFile, cacheSave: fileStorage.setFile);

  Future<bool> Function(List<int> data, String fileName)? get shellExporter =>
      TextMediaFileExporterForShell.exportFile;

  ///提交报告事件
  final onSubmitReport = FEventHandler<bool>();

  ///手机端提交报告
  final onMobileSubmitReport = FEventHandler<bool>();

  ///直接打印文档
  @override
  Future<void> directlyPrintPDF(String reportCode, String fileName) async {
    try {
      await _initPreviewReport(reportCode);
      try {
        PDFHelper.printPDF(fileName, reportDataPipe);
      } catch (e) {
        logger.e("print report error:", e);
      }
    } catch (e) {
      logger.e('InspectionReportController _initPreviewReport ex:', e);
    }
  }

  /// 直接打印图片
  @override
  Future<void> directlyPrintPDFJpges(
      List<String>? images, String fileName) async {
    try {
      PDFHelper.printPDFJpges(fileName, images);
    } catch (e) {
      logger.e("print report error:", e);
    }
  }

  ///打印文件（通过下载地址）
  @override
  Future<void> directlyPrintPDFFile(String fileUrl, String fileName) async {
    try {
      PDFHelper.printPDFFile(fileName, fileUrl);
    } catch (e) {
      logger.e("print report error:", e);
    }
  }

  @override
  List<FReportElementInfo> convertReportData(String jsonData) {
    List<FReportElementInfo> result = [];
    final infos = jsonDecode(jsonData) as List<dynamic>;
    for (var element in infos) {
      result.add(
        FReportElementInfo(
          key: element['Key'],
          tagId: element['TagId'],
          name: element['Name'],
          value: element['Value'],
        ),
      );
    }

    return result;
  }

  ///语音识别
  Future<String> commitASRInfoAsync(String token, String extension) async {
    try {
      var audioConvertResult = await rpc.aSR.commitASRInfoAsync(
        CommitASRInfoRequest(
          token: Store.user.token,
          url: token,
          fileType: extension,
        ),
      );
      return audioConvertResult.content ?? '';
    } catch (e) {
      logger.e('ReportEditController commitASRInfoAsync ex:', e);
    }
    return '';
  }

  ///直接下载图像PDF
  @override
  Future<void> directlyDownloadPDFJpges(
      List<String>? images, String fileName) async {
    try {
      PDFHelper.downloadPDFJpges(fileName, images, shellExporter);
    } catch (e) {
      logger.e("export report error:", e);
    }
  }

  ///直接下载 PDF 文件，通过 URL
  @override
  Future<void> directlyDownloadPDFFile(String fileUrl, String fileName) async {
    try {
      PDFHelper.downloadPDFFile(fileName, fileUrl, shellExporter);
    } catch (e) {
      logger.e("export report error:", e);
    }
  }

  ///直接下载文档报告
  @override
  Future<void> directlyDownloadPDF(String reportCode, String fileName) async {
    try {
      await _initPreviewReport(reportCode);
      try {
        PDFHelper.downloadPDF(fileName, reportDataPipe, shellExporter);
      } catch (e) {
        logger.e("export report error:", e);
      }
    } catch (e) {
      logger.e('InspectionReportController _initPreviewReport ex:', e);
    }
  }

  ///获取默认模板
  @override
  Future<String> getReportTemplate() async {
    final jsonStr = await Global.assetBundle.loadString(Store.app.isCurrChinese
        ? 'assets/templates/default.json'
        : 'assets/templates/default_en.json');
    return jsonStr;
  }

  /// 打开报告分享窗口
  ///
  /// [reportUrlToShare] 待分享的报告code
  @override
  Future<bool> openReportShareDialog(String? reportToShare) async {
    if (reportToShare == null || reportToShare.isEmpty) {
      return false;
    }
    var reportUrlToShare = await rpc.report.findReportShareUrlAsync(
        FindReportShareUrlRequest(
            languageCode: i18nBook.locale.toCodeString('-'),
            reportCode: reportToShare,
            token: Store.user.token));
    if (reportUrlToShare.isEmpty) {
      PromptBox.toast(i18nBook.auth.emptyReportShareAddress.t);
      return false;
    }

    router.dialog(
      () => ReportShareDialog(
        reportUrlToShare,
        reportToShare,
      ),
    );
    return true;
  }

  ///提交报告标签
  Future<bool> submitReportTags(
      String reportCode, List<String> selectedTags) async {
    try {
      final result =
          await rpc.report.modifyReportLabelsAsync(ModifyReportLabelsRequest(
        token: Store.user.token,
        reportCode: reportCode,
        reportLabels: selectedTags,
      ));
      return result;
    } catch (e) {
      logger.e('AddReportTagController submitReportTags ex:', e);
    }
    return false;
  }

  ///初始化标签所需数据
  ///
  /// [reportType] 默认值远程诊断
  Future<Map<ReportTagKey, List<String>>> getReportTagDatas(
    String recordCode, [
    ReportTypeEnum? reportType,
  ]) async {
    Map<ReportTagKey, List<String>> allReportTags = {};
    try {
      final labels = await rpc.report.findReportLabelsAsync(
        FindReportLabelsRequest(
          token: Store.user.token,
          languageCode: i18nBook.locale.toCodeString('-'),
          recordCode: recordCode,
          reportType: reportType ?? ReportTypeEnum.RemoteDiagnosis,
        ),
      );
      labels.forEach((label) {
        final tagKey =
            ReportTagKey(label.reportLabelCode ?? '', label.labelName ?? '');
        if (!allReportTags.containsKey(tagKey)) {
          allReportTags[tagKey] = label.labelItems ?? [];
        } else {
          logger.e(
              'AddReportTagController _initDatas contains duplicate labels :' +
                  tagKey.code);
        }
      });
    } catch (e) {
      logger.e('ReportManager getReportTagDatas ex:', e);
    }
    return allReportTags;
  }

  @override
  Future<List<ReportDTO>> findReportsAsync(String recordCode) async {
    var reportInfo = await rpc.report.findReportsAsync(
      FindReportsRequest(
        token: Store.user.token,
        recordCode: recordCode,
        languageCode: i18nBook.locale.toCodeString('-'),
      ),
    );
    return reportInfo;
  }

  ///获取报告提交内容信息Json
  String getMobileReportDatasJson({
    String? patientName,
    String? patientSex,
    String? age,
    List<String>? imageInfos,
    String? des,
    String? summary,
    String? creatorName,
    String? fullName,
    String? customDoctor,
    String? customOrganzation,
    String? deviceOrganzationName,
  }) {
    final isChinese = Store.app.isCurrChinese;
    List<dynamic> jsonItems = [];

    var orgName = customOrganzation.isNullOrEmpty
        ? Store.user.rootOrganizationName
        : customOrganzation;
    if (orgName.isNullOrEmpty) {
      orgName = deviceOrganzationName;
    }

    ///医院名称
    final hospitalNameMap = <String, dynamic>{};
    hospitalNameMap['Key'] = '017ce934-446f-423d-be66-664aeb89c217';
    hospitalNameMap['Value'] = orgName;
    hospitalNameMap['Name'] = 'HospitalName';
    hospitalNameMap['TagId'] = '7abbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(hospitalNameMap);

    ///病人姓名
    final patientNameMap = <String, dynamic>{};
    patientNameMap['Key'] = isChinese
        ? '97ec1395-3e8d-4ca9-a36a-0baace5646da'
        : '98d9600b-3d4e-4413-ad81-d12133c9d817';
    patientNameMap['Value'] = patientName ?? '';
    patientNameMap['Name'] = 'PatientName';
    patientNameMap['TagId'] = '91bbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(patientNameMap);

    ///病人性别
    final patientSexMap = <String, dynamic>{};
    patientSexMap['Key'] = isChinese
        ? 'f2e65e15-1a55-47ca-9e6c-42f9e8659daf'
        : 'f6c50df4-06e2-4c1f-a21e-ffef3833f234';
    patientSexMap['Value'] = patientSex;
    patientSexMap['Name'] = 'PatientGender';
    patientSexMap['TagId'] = '93bbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(patientSexMap);

    ///病人年龄
    final patientAgeMap = <String, dynamic>{};
    patientAgeMap['Key'] = isChinese
        ? 'b84a9cbb-1b06-49b4-b8c5-6b2a57e24a58'
        : 'ac472a5a-9d45-46c4-8362-1ad7ba51e90d';
    patientAgeMap['Value'] = age;
    patientAgeMap['Name'] = 'PatientAge';
    patientAgeMap['TagId'] = '92bbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(patientAgeMap);

    ///图像集合
    final imagesMap = <String, dynamic>{};
    imagesMap['Key'] = isChinese
        ? 'cc81bba9-8d32-4389-a18e-f64ac3890ec9'
        : '5cc4fbbe-9729-4577-a087-30f8eafcfed0';
    imagesMap['Value'] = imageInfos;
    imagesMap['Name'] = 'ReportImages';
    imagesMap['TagId'] = '9fbbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(imagesMap);

    ///超声描述
    final descriptionMap = <String, dynamic>{};
    descriptionMap['Key'] = isChinese
        ? 'e9e4b446-2f64-479c-8e15-cdda067cd00b'
        : '33e272e5-c9a9-4ebb-a813-389de1f48481';
    descriptionMap['Value'] = des ?? '';
    descriptionMap['Name'] = 'ReportDescription';
    descriptionMap['TagId'] = '9dbbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(descriptionMap);

    ///超声提示
    final summaryMap = <String, dynamic>{};
    summaryMap['Key'] = isChinese
        ? '8b498af9-fbe4-4bfa-b3eb-2b02ebd785a1'
        : '9af5ee42-1ff7-4fa0-8bcd-1abee897661c';
    summaryMap['Value'] = summary;
    summaryMap['Name'] = 'ReportSummary';
    summaryMap['TagId'] = '9ebbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(summaryMap);

    ///报告时间
    final reportTimeMap = <String, dynamic>{};
    reportTimeMap['Key'] = isChinese
        ? '415df52f-3fef-46c5-a39f-c3e3090e79f2'
        : '6bca4c98-5087-451c-9aa6-9e103d2919ca';
    reportTimeMap['Value'] =
        DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();
    reportTimeMap['Name'] = 'ReportTime';
    reportTimeMap['TagId'] = '4abbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(reportTimeMap);

    ///检查医师
    final inspectionMap = <String, dynamic>{};
    inspectionMap['Key'] = isChinese
        ? '35fbecf3-7900-479d-8d97-2daf23150be6'
        : '630a046d-2d60-4fd9-9117-ac27f802f016';
    inspectionMap['Value'] =
        customDoctor.isNullOrEmpty ? creatorName : customDoctor;
    inspectionMap['Name'] = 'InspectionPhysician';
    inspectionMap['TagId'] = isChinese
        ? '6abbaa61-a91d-4399-a3f4-df29117d2d59'
        : '5abbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(inspectionMap);

    ///报告医师
    final reporterMap = <String, dynamic>{};
    reporterMap['Key'] = '5c51bdd6-6a10-40d3-8bcf-5a6a952d8ec7';
    reporterMap['Value'] = Store.user.displayName;
    reporterMap['Name'] = 'ReportPhysician';
    reporterMap['TagId'] = '5abbaa61-a91d-4399-a3f4-df29117d2d59';
    jsonItems.add(reporterMap);
    return jsonEncode(jsonItems);
  }

  /// 格式化时间
  ///
  /// [time] 后端返回的时间
  @override
  String getTime(String time) {
    String stringTime = '';
    if (time.isNotEmpty) {
      stringTime = DateFormat("yyyy-MM-dd HH:mm:ss").format(
        DateTime.fromMillisecondsSinceEpoch(
          DateTime.tryParse(time)?.millisecondsSinceEpoch as int,
        ),
      );
    }
    return stringTime;
  }

  ///打开报告编辑页面
  @override
  Future<void> openReportEdit(
    String patientCode, {
    String consultationCode = '',
    String recordCode = '',
    String reportCode = '',
    int patientTab = 0,
    String referralRecordCode = '',

    ///reportEditSource这个参数目前只有群组中会传入，暂不可作为区分实时或分时的依据
    ReportEditSource reportEditSource = ReportEditSource.VSono,
  }) async {
    final url = html.window.location.origin;
    final token = Store.user.token;
    var languageCode = i18nBook.locale.toCodeString("-");
    logger.i(
        "ReportManager edit report, recordCode: $recordCode, patientCode: $patientCode.");
    if (reportEditSource == ReportEditSource.UserGroup) {
      ///用户群组功能中写报告目前仅需支持主窗口打开写报告
      _openReportEditPage(
        token,
        patientCode,
        referralRecordCode,
        reportCode,
        consultationCode,
        recordCode,
        reportEditSource: reportEditSource,
      );
      return;
    }
    if (FPlatform.isPureWeb) {
      if (Store.app.enableNewTab) {
        html.window.open(
            '$url/index.html?page=report&patientCode=$patientCode&token=$token&reportCode=$reportCode&recordCode=$recordCode&referralRecordCode=$referralRecordCode&lagCode=$languageCode&consultationCode=$consultationCode',
            '');
      } else {
        _openReportEditPage(token, patientCode, referralRecordCode, reportCode,
            consultationCode, recordCode);
      }
    } else if (FPlatform.isMacOS || FPlatform.isWindows) {
      if (LocalSetting.ins.isUseSecondWindow!) {
        logger.i(
            "ReportManager Use second window edit report, recordCode: $recordCode, patientCode: $patientCode,reportCode:$reportCode,referralRecordCode:$referralRecordCode,consultationCode:$consultationCode.");
        rpc.platform.openReportEditAsync(Store.user.token, patientCode,
            reportCode, recordCode, referralRecordCode, consultationCode);
      } else {
        _openReportEditPage(token, patientCode, referralRecordCode, reportCode,
            consultationCode, recordCode);
      }
    } else {
      _openReportEditPage(token, patientCode, referralRecordCode, reportCode,
          consultationCode, recordCode);
    }
  }

  /// 根据扫查记录获取转诊扫查图像详情
  @override
  Future<RemedicalListResult> queryReferralRemedicalListByRecordInfoAsync(
      String recordCode, String referralRecordCode) async {
    try {
      final getRecordsPage =
          await rpc.remedical.queryReferralRemedicalListByRecordInfoAsync(
        QueryReferralExamReportRequest(
          token: Store.user.token,
          recordCode: recordCode,
          referralRecordCode: referralRecordCode,
        ),
      );
      return getRecordsPage;
    } catch (e) {
      return RemedicalListResult();
    }
  }

  ///打开报告编辑页
  void _openReportEditPage(
    String token,
    String patientCode,
    String referralRecordCode,
    String reportCode,
    String consultationCode,
    String recordCode, {
    ReportEditSource? reportEditSource,
  }) {
    var arguments = {
      'token': token,
      'patientCode': patientCode,
      'referralRecordCode': referralRecordCode,
      'reportCode': reportCode,
      'consultationCode': consultationCode,
      'recordCode': recordCode,
    };
    if (reportEditSource != null) {
      arguments['reportEditSource'] = reportEditSource.name;
    }

    ///SP60全屏显示撰写报告
    router.to(
      RouteNames.Remedical.ReportEdit,
      id: NavIds.HOME,
      parameters: arguments,
    );
  }

  ///进入测量页面
  void enterVidMeasurePage({
    String imageUrl = '',
    int imageindex = 0,
    String remedicalCode = '',
    String patientCode = '',
    String recordCode = '',
    VidImageSource source = VidImageSource.Consultation,
    String? remedicalAISelectedInfoCode = '',
    bool needRouterBack = false,
    bool reportPageEnter = false,
  }) {
    final token = Store.user.token;
    //壳子下
    var isShell = FPlatform.isWindows || FPlatform.isMacOS;
    if (isShell) {
      //多窗口模式且非SP60
      if (LocalSetting.ins.isUseSecondWindow! &&
          !CartSystemPlatform.isCartSystemVersion &&
          !reportPageEnter) {
        rpc.platform.openImageMeasureAsync(
            Store.user.token, patientCode, remedicalCode, recordCode);
      } else {
        ///壳子下单窗口模式
        _setMeasureCurrentRouter();
        _openMeasurePage(
          patientCode,
          remedicalCode,
          recordCode,
          source.index,
          remedicalAISelectedInfoCode,
          needRouterBack: needRouterBack,
          reportPageEnter: reportPageEnter,
        );
      }
    } else {
      ///web端开启新标签页
      if (Store.app.enableNewTab) {
        final url = html.window.location.origin;
        var languageCode = i18nBook.locale.toCodeString("-");
        html.window.open(
            '$url/index.html?page=measure&token=$token&patientCode=$patientCode&remedicalCode=$remedicalCode&recordCode=$recordCode&lagCode=$languageCode&source=${source.index.toString()}&remedicalAISelectedInfoCode=$remedicalAISelectedInfoCode',
            '');
      } else {
        ///web端本地路由
        _setMeasureCurrentRouter();
        _openMeasurePage(
          patientCode,
          remedicalCode,
          recordCode,
          source.index,
          remedicalAISelectedInfoCode,
          needRouterBack: needRouterBack,
          reportPageEnter: reportPageEnter,
        );
      }
    }
  }

  ///设置当前路由为测量
  void _setMeasureCurrentRouter() {
    try {
      var controller = Get.find<HomeController>();
      controller.state.currentRouter = RouteNames.Remedical.Measure;
    } catch (e) {}
  }

  @override
  Future<RemedicalListResult> getRemedicalListByRecordInfoAsync(
      String recordCode) async {
    try {
      final result = await rpc.remedical.getRemedicalListByRecordInfoAsync(
        QueryRecordRequest(
          token: Store.user.token,
          recordCode: recordCode,
        ),
      );
      return result;
    } catch (e) {
      return RemedicalListResult();
    }
  }

  ///注册微信分享api
  @override
  void initFluwx() async {
    try {
      if (kIsMobile) {
        await registerWxApi(
          appId: "wx2167274095118ddb",
          doOnAndroid: true,
          doOnIOS: true,
          universalLink: "https://flyinsono.com/",
        );
      }
    } catch (e) {
      logger.e('ReportManager initFluwx', e);
    }
  }

  /// 获取测量图像
  @override
  Future<List<RemedicalMeasuredInfoDTO>> findRemedicalMeasuredInfoAsync(
    String recordCode, {
    BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.RemoteDiagnosis,
  }) async {
    List<RemedicalMeasuredInfoDTO> remedicalMeasured = [];
    try {
      final result = await rpc.recordInfo.findRemedicalMeasuredInfoAsync(
        FindRemedicalMeasuredInfoRequest(
          token: Store.user.token,
          recordCode: recordCode,
          businessType: businessTypeEnum,
        ),
      );
      remedicalMeasured = result;
    } catch (e) {
      remedicalMeasured = [];
      printError(
          info: "findRemedicalMeasuredInfoAsync exception:" + e.toString());
      logger.e("findRemedicalMeasuredInfoAsync exception:", e);
    }
    return remedicalMeasured;
  }

  ///跟据reportCode获取报告详情
  @override
  Future<ReportDTO> findReportByCodeAsync(String reportCode) async {
    final reportInfo = await rpc.report.findReportByCodeAsync(
      FindReportByCodeRequest(
        token: Store.user.token,
        reportCode: reportCode,
        language: i18nBook.locale.toCodeString('-'),
      ),
    );
    return reportInfo;
  }

  ///手机端底部弹窗选择分享方式
  @override
  Future<bool> showBottomSheet(ReportDTO reportInfo) async {
    bool result = false;

    var reportCode = reportInfo.reportCode ?? '';
    final url = await findReportShareUrlAsync(reportCode);
    String smsContent = i18nBook.remedical.smsShare
        .translate([(reportInfo.patientName), '：' + url + '，']);
    smsContent = smsContent.replaceAll('#', '%23');
    await showModalBottomSheet(
        context: Get.context!,
        backgroundColor: Colors.white, //背景颜色
        shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.only(
                topLeft: Radius.circular(8), topRight: Radius.circular(8))),
        isScrollControlled: false,
        isDismissible: true,
        builder: (BuildContext context) {
          return Column(
            mainAxisSize: MainAxisSize.min, // 设置最小的弹出
            children: [
              ListTile(
                leading: Icon(Icons.wechat),
                title: Text(i18nBook.remedical.wechatFriend.t),
                onTap: () async {
                  _shareWX(url, reportInfo.patientName);
                  router.back();
                },
              ),
              RowSeparator(),
              ListTile(
                leading: Icon(Icons.message),
                title: Text(i18nBook.remedical.messageShare.t),
                onTap: () async {
                  _sendSMS(smsContent, []);
                  router.back();
                },
              ),
              RowSeparator(),
              ListTile(
                leading: Icon(Icons.copy),
                title: Text(i18nBook.remedical.copyLink.t),
                onTap: () {
                  if (FPlatform.isWindows || FPlatform.isMacOS) {
                    rpc.platform.copyToClipboard(url);
                  } else {
                    Clipboard.setData(ClipboardData(text: url));
                  }
                  PromptBox.toast(i18nBook.remedical.copySuccess.t);

                  router.back();
                },
              ),
            ],
          );
        });
    return result;
  }

  ///微信分享
  Future<void> _shareWX(String url, String? patientName) async {
    var result = await isWeChatInstalled;
    if (!result) {
      PromptBox.toast(i18nBook.remedical.noOpenWx.t);
      return;
    }
    //分享后打开的图文连接
    String linkUrl = url;
    //分享的小图片
    String imageUrl =
        "https://flyinsono-bj-1300984704.cos.ap-beijing.myqcloud.com/FlyinsonoIcon.png";

    /// 分享到好友
    WeChatShareBaseModel model = WeChatShareWebPageModel(
      //链接
      linkUrl,
      //标题
      title: i18nBook.remedical.ultrasoundReport.t,
      //描述
      description: patientName ?? " ",
      //小图
      thumbnail: WeChatImage.network(imageUrl),
      //微信消息
      scene: WeChatScene.SESSION,
    );
    final rst = await shareToWeChat(model);
    logger.i("ReportManager - share by wechat|$rst|$linkUrl");
  }

  void _sendSMS(String message, List<String> recipents) async {
    if (FPlatform.isAndroid) {
      // await launchUrl(Uri.parse('sms:?body=$message'));
      await launch('sms:?body=$message'); // 修正乱码问题
    } else {
      String _result = await sendSMS(message: message, recipients: recipents)
          .catchError((onError) {
        print(onError);
      });
      print(_result);
    }
  }

  @override
  Future<List<ReportDTO>> getReportInfoAsync(String recordCode) async {
    try {
      var result = await findReportsAsync(recordCode);
      return result;
    } catch (e) {
      logger.e('RealTimeConsultationReportController getFollowUpVisitInfo ex:' +
          e.toString());
      return [];
    }
  }

  ///获取分享报告链接
  @override
  Future<String> findReportShareUrlAsync(String reportCode) async {
    var reportUrlToShare = await rpc.report.findReportShareUrlAsync(
        FindReportShareUrlRequest(
            languageCode: i18nBook.locale.toCodeString('-'),
            reportCode: reportCode,
            token: Store.user.token));
    return reportUrlToShare;
  }

  ///打开报告预览页面
  @override
  Future<void> openReportPreviewPage(
    String recordCode,
    String referralRecordCode, {
    String reportCode = '',
  }) async {
    try {
      logger.i("ReportManager findReportsAsync recordCode:$recordCode");
      final reports = await findReportsAsync(recordCode);
      if (reports.isEmpty) {
        PromptBox.toast(i18nBook.remedical.noReport.t);
        return;
      }

      ReportPreviewController.isFromEditor = false;
      final url = html.window.location.origin;
      final token = Store.user.token;
      var languageCode = i18nBook.locale.toCodeString("-");
      logger.i(
          "ReportManager findReportsAsync recordCode:'$url/index.html?page=reportPreview&token=$token&reportCode=$reportCode&recordCode=$recordCode&referralRecordCode=$referralRecordCode&lagCode=$languageCode'");
      if (FPlatform.isPureWeb && Store.app.enableNewTab) {
        html.window.open(
            '$url/index.html?page=reportPreview&token=$token&reportCode=$reportCode&recordCode=$recordCode&referralRecordCode=$referralRecordCode&lagCode=$languageCode',
            '');
      } else if ((FPlatform.isMacOS || FPlatform.isWindows) &&
          LocalSetting.ins.isUseSecondWindow!) {
        rpc.platform.openReportPreviewAsync(token, reportCode, recordCode,
            ReportPreviewController.isFromEditor.toString());
      } else {
        _openReportPreview(token, reportCode, recordCode);
      }
    } catch (e) {
      printError(
          info: "getRemedicalListByRecordInfoAsync exception:" + e.toString());
      logger.e("getRemedicalListByRecordInfoAsync exception:", e);
    }
  }

  void _openReportPreview(String token, String reportCode, String recordCode) {
    var arguments = {
      'token': token,
      'reportCode': reportCode,
      'recordCode': recordCode,
    };
    router.to(
      RouteNames.Remedical.ReportPreview,
      id: NavIds.HOME,
      parameters: arguments,
    );
  }

  Future<void> _initPreviewReport(String reportCode) async {
    try {
      if (reportCode.isNotEmpty) {
        final reportInfo = await rpc.report.findReportByCodeAsync(
          FindReportByCodeRequest(
            token: Store.user.token,
            reportCode: reportCode,
          ),
        );
        final jsonStr = reportInfo.reportDatasJson;
        final measureJsonStr = reportInfo.reportMeasureDatasJson;
        if (jsonStr != null && jsonStr.isNotEmpty) {
          final jsonItems = jsonDecode(jsonStr) as List<dynamic>;
          if (measureJsonStr.isNotNullOrEmpty) {
            final measureJsonItems =
                jsonDecode(measureJsonStr!) as List<dynamic>;
            jsonItems.addAll(measureJsonItems);
          }
          var reportTemplate = reportInfo.reportTemplateJson;

          var reportTempalteDoc =
              ReportTemplateDocument.fromJson(jsonDecode(reportTemplate!));
          report.FReportInfo.instance.init(
            reportTempalteDoc,
            DateTime.now(),
            "",
            revoke: i18nBook.common.revoke.t,
            selectEntry: i18nBook.remedical.selectWord.t,
            selectImageHint: i18nBook.remedical.clickAndSelectImage.t,
          );
          report.FReportInfo.instance.fromJson(jsonItems);
        }
      }
    } catch (e) {
      print(e);
    }
  }

  void _openMeasurePage(
    String patientCode,
    String remedicalCode,
    String recordCode,
    int type,
    String? remedicalAISelectedInfoCode, {
    bool needRouterBack = false,
    bool reportPageEnter = false,
  }) async {
    var parasmeters = {
      "page": "measure",
      "patientCode": patientCode,
      "remedicalCode": remedicalCode,
      "recordCode": recordCode,
      "source": type.toString(),
      "token": Store.user.token,
      "remedicalAISelectedInfoCode": remedicalAISelectedInfoCode ?? '',
    };

    /// parasmeters 添加参数 needBack
    parasmeters["needRouterBack"] = needRouterBack.toString();
    await router.to(
      RouteNames.Remedical.Measure,
      id: (kIsMobile || (reportPageEnter && needRouterBack))
          ? null
          : NavIds.HOME,
      parameters: parasmeters,
    );
  }
}

// enum VidImageSource {
//   Remedical,
//   Consultation,
//   Laboratory,
//   AiResultModifier,
// }
