import 'dart:convert';

import 'package:fis_common/helpers/encrypt.dart';
import 'package:fis_common/index.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_lib_pdf/pdf_helper.dart';
import 'package:fis_lib_report/report_info/element_tag_names.dart';
import 'package:fis_lib_report/report_info/input_text_info.dart';
import 'package:fis_lib_report/report_info/report_info.dart';
import 'package:fis_i18n/i18n.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/services/entity/report_editor_setting.dart';
import 'package:flyinsono/architecture/services/modules/report_editor_configuration.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/architecture/storage/file_storage.dart';
import 'package:flyinsono/architecture/utils/web_parameter_helpler.dart';
import 'package:flyinsono/architecture/values/features.dart';
import 'package:flyinsono/managers/interfaces/entities/reportEditSource.dart';
import 'package:flyinsono/pages/remedical/report/report_edit/controller.dart';
import 'package:flyinsono/pages/remedical/report/report_edit/state.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;

class ReportOperateController {
  late final ReportEditController controller;
  late final ReportEditState state;
  late final ReportPreviewController reportPreviewController =
      Get.put<ReportPreviewController>(ReportPreviewController());

  /// 本地报告编辑器持久化缓存服务
  late final LocalReportEditorService localReportEditorService =
      Get.find<LocalReportEditorService>();
  late final ReportEditorSetting reportEditorSetting = ReportEditorSetting.ins;
  ReportDataPipe get fileStorage => ReportDataPipe(
      cacheGet: reportPreviewController.fileStorage.getFile,
      cacheSave: reportPreviewController.fileStorage.setFile);
  String get reportName => _getReportName();
  Future<bool> Function(List<int> data, String fileName)? get shellExporter =>
      TextMediaFileExporterForShell.exportFile;
  ReportOperateController(ReportEditController controller) {
    this.controller = controller;
    this.state = controller.state;
  }

  ///跟据reportCode获取报告详情
  Future<ReportDTO> findReportByCodeAsync() async {
    final reportInfo =
        await rpc.report.findReportByCodeAsync(FindReportByCodeRequest(
      token: Store.user.token,
      reportCode: state.reportCode,
    ));
    return reportInfo;
  }

  //提交报告
  Future<void> submitReport() async {
    try {
      final reportInfo = FReportInfo.instance;
      reportInfo.toJson();

      ///noTagIdItems:测量数据
      var noTagIdItems = reportInfo.jsonItems
          .where((element) =>
              element['TagId'] == null ||
              element['TagId'].toString().isNullOrEmpty)
          .toList();
      var normalItems = reportInfo.jsonItems
          .where((element) =>
              element['TagId'] != null &&
              element['TagId'].toString().isNotEmpty)
          .toList();
      final reportInfoJson = jsonEncode(normalItems);
      final reportMeasureDatasJson = jsonEncode(noTagIdItems);
      final templateJson = (state.selectedTemplate.reportTemplateJson);
      String recordCode = state.recordCode;
      if (recordCode.isEmpty) {
        recordCode = state.consultationCode;
      }
      final patientNameElementInfo = FReportInfo.instance
          .getElementInfoByTagName(TagNames.PATIENT_NAME_TAG);
      var name = '';
      if (patientNameElementInfo != null) {
        final patientNameInfo = patientNameElementInfo as InputTextInfo;
        name = patientNameInfo.text;
      }
      bool result = false;
      if (state.reportCode.isNotEmpty) {
        result = await modifyReport(
          recordCode,
          templateJson ?? '',
          name,
          reportInfoJson,
          reportMeasureDatasJson,
        );
      } else {
        final addResult = await addReport(
          recordCode,
          templateJson ?? '',
          name,
          reportInfoJson,
          reportMeasureDatasJson,
        );
        if (addResult.isNotEmpty) {
          result = true;
          state.reportCode = addResult;
          if (FPlatform.isWindows || FPlatform.isMacOS)
            rpc.platform.onSubmitReport(state.patientId, recordCode);
        }
      }
      if (result) {
        controller.reportManager.onSubmitReport.emit(this, result);

        /// 提交则清空缓存
        reportEditorSetting.setReportDraft("", "");
        localReportEditorService.save();
        if (Store.user.hasFeature(FeatureKeys.EditReportTag) &&
            Store.user.enableReportLabel) await controller.openAddReportTag();
        //  PromptBox.toast(i18nBook.remedical.submitSuccess.t);
        controller.updateReportCacheByRecordCode(recordCode);
        logger.i(
            'LocalSetting.ins.isUseSecondWindow! :${LocalSetting.ins.isUseSecondWindow!}');
        if (state.reportEditSource == ReportEditSource.UserGroup) {
          ///用户群组编辑报告，直接返回即可
          controller.back();
          return;
        }
        if ((FPlatform.isWindows || FPlatform.isMacOS) &&
            LocalSetting.ins.isUseSecondWindow!) {
          await rpc.platform.refershReports();
        } else if (((FPlatform.isMacOS || FPlatform.isWindows) &&
                !LocalSetting.ins.isUseSecondWindow!) ||
            (FPlatform.isPureWeb && !Store.app.enableNewTab)) {
          controller.back();
        }

        if (FPlatform.isPureWeb && ParameterHelper.parasmeters.length > 1) {
          html.window.close();
        }
      }
    } catch (e) {
      logger.e('ReportOperateController submitReport ex:', e);
    }
  }

  ///修改报告请求
  Future<bool> modifyReport(
    String recordCode,
    String templateJson,
    String name,
    String reportInfoJson,
    String? reportMeasureDatasJson,
  ) async {
    var reportInfo = await findReportByCodeAsync();
    final updateRequest = ModifyReportRequest(
      reportCode: state.reportCode,
      token: Store.user.token,
      recordCode: recordCode,
      reportType: state.consultationCode.isNotEmpty
          ? ReportTypeEnum.LiveConsultation
          : ReportTypeEnum.RemoteDiagnosis,
      reportTemplateJson: templateJson,
      platformLabels: ["Flyinsono", "PC", "RemoteDiagnosis"],
      patientName: FEncryptHelper.encodeBase64(name),
      reportDatasJson: reportInfoJson,
      reportMeasureDatasJson: reportMeasureDatasJson,
      reportOrgan: reportInfo.reportOrgan,
    );
    if (state.referralRecordCode.isNotEmpty) {
      updateRequest.referralRecordCode = state.referralRecordCode;
    }
    return await rpc.report.modifyReportAsync(updateRequest);
  }

  /// 打开报告预览页面
  Future<void> openReportPreviewer() async {
    try {
      ReportPreviewController.isFromEditor = true;
      print(
          'reportCode:' + state.reportCode + ' recordCode:' + state.recordCode);
      bool needBackToHome = false;

      /// 判断是否为多窗口或多标签页，多窗口的情况下不需要返回首页
      if (FPlatform.isWindows || FPlatform.isMacOS) {
        needBackToHome = !LocalSetting.ins.isUseSecondWindow!;
      } else if (FPlatform.isPureWeb) {
        needBackToHome = !Store.app.enableNewTab;
      }

      await router.to(RouteNames.Remedical.ReportPreview,
          parameters: {
            'reportCode': state.reportCode,
            'recordCode': state.recordCode
          },
          id: needBackToHome ? NavIds.HOME : null);
    } catch (e) {
      printError(info: "preview report error:" + e.toString());
      logger.e("preview report error:", e);
    }
  }

  /// 直接打印报告
  Future<void> printReportDirectly() async {
    try {
      PDFHelper.printPDF(reportName, fileStorage);
    } catch (e) {
      logger.e("print report error:", e);
    }
  }

  /// 直接导出报告
  Future<void> exportReportDirectly() async {
    try {
      await PDFHelper.downloadPDF(
        reportName,
        fileStorage,
        shellExporter,
      );
      // mock wait
      await Future.delayed(const Duration(milliseconds: 500));
    } catch (e) {
      logger.e("export report error:", e);
    }
  }

  ///获取病人信息
  Future<ClientPatientInfoDTO?> getPatientInfo(String patientCode) async {
    try {
      print('Store.user.token: ' + Store.user.token);
      if (patientCode.isNullOrEmpty) {
        return ClientPatientInfoDTO();
      }
      final patientInfo = await rpc.patient.findPatientByCodeAsync(
        FindPatientByCodeRequest(
          code: patientCode,
          token: Store.user.token,
        ),
      );
      return patientInfo;
    } catch (e) {
      logger.e('ReportEditController getPatientInfo ex:', e);
      return null;
    }
  }

  ///新增报告请求
  Future<String> addReport(
    String recordCode,
    String templateJson,
    String name,
    String reportDatasJson,
    String? reportMeasureDatasJson,
  ) async {
    final addRequest = AddReportRequest(
      token: Store.user.token,
      recordCode: recordCode,
      reportType: state.consultationCode.isNotEmpty
          ? ReportTypeEnum.LiveConsultation
          : ReportTypeEnum.RemoteDiagnosis,
      reportTemplateJson: templateJson,
      isReferral: state.referralRecordCode.isNotEmpty,
      reportDatasJson: reportDatasJson,
      reportMeasureDatasJson: reportMeasureDatasJson,
      platformLabels: [
        "Flyinsono",
        FPlatform.isPureWeb ? "Web" : "PC",
        "RemoteDiagnosis"
      ],
      patientName: FEncryptHelper.encodeBase64(name),
    );
    return await rpc.report.addReportAsync(addRequest);
  }

  String _getReportName() {
    var reportInfo = FReportInfo.instance;
    var inputTextInfo;
    String patientName = '';
    var patientElement =
        reportInfo.getElementInfoByTagName(TagNames.PATIENT_NAME_TAG);
    if (patientElement != null) {
      inputTextInfo = patientElement as InputTextInfo;
      patientName = inputTextInfo.text;
    } else {
      patientName = "";
    }
    final nameStr = patientName.replaceAll("*", "x");
    final patientIdStr = reportInfo.patinentId ?? i18nBook.remedical.notFill.t;
    DateFormat format = DateFormat("yyyMMddHHmmss");
    final reportTime = reportInfo.reportDate ?? DateTime.now();
    final reportTimeStr = format.format(reportTime);
    final fileName = "${nameStr}_${patientIdStr}_$reportTimeStr.pdf";
    return fileName;
  }
}
