import 'package:fis_common/helpers/encrypt.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_ui/index.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/services/modules/config_language.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/managers/base_manager.dart';
import 'package:flyinsono/pages/main/home/controller.dart';
import 'package:flyinsono/rpc.dart';
import 'package:flyinsono/utils/utc_dateTime_converter.dart';
import 'package:flyinsono/views/desktop/real_time_consultation/widgets/simple_Info.dart';
import 'package:get/get.dart';
import 'package:fis_common/logger/logger.dart';
import 'interfaces/entities/patient_Info.dart';
import 'interfaces/entities/process_arg.dart';
import 'interfaces/remedical.dart';
import 'package:fis_common/index.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:universal_html/html.dart' as html;
import 'package:fis_common/event/event_type.dart';

class RemedicalManager extends BaseManager implements IRemedicalManager {
  final processChange = FEventHandler<ProcessArg>();

  /// 语言服务
  final languageService = Get.find<LanguageService>();
  @override
  Future<PageResult<ClientPatientInfoBaseDTO>> findPatients({
    int pageIndex = 1,
    int pageSize = 20,
    String keyWord = '',
    DateTime? startDateTime,
    DateTime? endDateTime,
    PatientValidStatusEnum isValid = PatientValidStatusEnum.All,
  }) async {
    final patients = await rpc.patient.findPatientsAsync(
      FindPatientsPageRequest(
        token: token,
        pageIndex: pageIndex,
        pageSize: pageSize,
        keyWord: keyWord,
        startTime: startDateTime,
        endTime: endDateTime,
        isValid: isValid,
      ),
    );
    return patients;
  }

  @override
  Future<bool> createPatientByUnregisteredAsync(String patientName,
      {String? code}) async {
    final name = FEncryptHelper.encodeBase64(patientName);
    final result = await rpc.patient.createPatientByUnregisteredAsync(
      CreatePatientByUnregisteredRequest(
        token: token,
        patientName: name,
        unregisteredPatientCode: code,
      ),
    );
    return result;
  }

  @override
  Future<String> createUnregisteredPatient(String patientName,
      {String? code}) async {
    final name = FEncryptHelper.encodeBase64(patientName);
    final result = await rpc.patient.createUnregisteredPatientAsync(
      CreatePatientByUnregisteredRequest(
        token: token,
        patientName: name,
        unregisteredPatientCode: code,
      ),
    );
    return result;
  }

  @override
  Future<List<SimpleInfoItem>> findSimpleInfoPatients({
    int pageIndex = 1,
    int pageSize = 20,
    String keyWord = '',
    DateTime? startDateTime,
    DateTime? endDateTime,
    PatientValidStatusEnum isValid = PatientValidStatusEnum.All,
    bool isCounsultationPatient = false,
  }) async {
    PageResult<ClientPatientInfoBaseDTO> patients;
    if (isCounsultationPatient) {
      patients = await rpc.liveConsultation.findConsultationPatientAsync(
        FindConsultationPatientPageRequest(
          token: Store.user.token,
          keyword: keyWord,
          pageIndex: pageIndex,
          pageSize: pageSize,
        ),
      );
    } else {
      patients = await findPatients(
        keyWord: keyWord,
        pageIndex: pageIndex,
        pageSize: pageSize,
        startDateTime: startDateTime,
        endDateTime: endDateTime,
      );
    }
    List<SimpleInfoItem> items = [];
    for (ClientPatientInfoBaseDTO p in patients.pageData ?? []) {
      List<DataItemDTO> patientData = p.patientData ?? [];
      var identityCard = patientData
          .firstWhereOrNull((element) => element.key == 'IdentityCard');
      items.add(
        SimpleInfoItem(
          itemCode: p.patientCode ?? '',
          name: _getPatientName(patientData),
          image: patientData
              .firstWhereOrNull((element) => element.key == 'HeadImgUrl')
              ?.value,
          role: patientData
              .firstWhereOrNull((element) => element.key == 'Phone')
              ?.value,
          des: [
            identityCard == null ? '' : identityCard.value,
          ],
        ),
      );
    }
    return items;
  }

  String? _getPatientName(List<DataItemDTO> patientData) {
    var name =
        patientData.firstWhereOrNull((element) => element.key == 'Name')?.value;
    if (name == null || name.isEmpty) {
      name = patientData
          .firstWhereOrNull((element) => element.key == 'AnimalInfoName')
          ?.value;
    }
    return name;
  }

  @override
  PatientInfo dtoConvertToPatientInfo(ClientPatientInfoDTO patientInfoDto) {
    var patientData = patientInfoDto.patientData ?? [];
    var encryptFullName = patientInfoDto.encryptFullName ?? '';
    var name = getKeyValue(patientData, ['Name', 'AnimalInfoName']);
    var phone = getKeyValue(patientData, ['Phone', 'AnimalInfoPhone']);
    var id = getKeyValue(
      patientData,
      ['IdentityCard', 'AnimalInfoIdentityCard'],
    );
    var insuranceCode = getKeyValue(patientData, ['InsuranceCode']);
    var sex = getKeyValue(
      patientData,
      ['Sex', 'AnimalInfoSex'],
    );
    return PatientInfo(
      patientCode: patientInfoDto.patientCode ?? '',
      createTime: patientInfoDto.createTime,
      isValid: patientInfoDto.isValid,
      isReferral: patientInfoDto.isReferral,
      name: name,
      phone: phone,
      insuranceCode: insuranceCode,
      identityCard: id,
      visibleName: FEncryptHelper.decryptBase64(encryptFullName),
      age: getKeyValue(
        patientData,
        ['Age', 'AnimalInfoAge'],
      ),
      sex: sex,
      headImgUrl: getKeyValue(
        patientData,
        ['HeadImgUrl', 'AnimalInfoHeadImgUrl'],
      ),
      species: getKeyValue(patientData, ['Species']),
      breed: getKeyValue(patientData, ['Breed']),
      birthday: getKeyValue(
        patientData,
        ['Birthday'],
      ),
      ageUnits: getKeyValue(
        patientData,
        ['AgeUnits'],
      ),
      ageYear: getKeyValue(
        patientData,
        ['AgeYear'],
      ),
      ageMonth: getKeyValue(
        patientData,
        ['AgeMonth'],
      ),
      ageWeek: getKeyValue(
        patientData,
        ['AgeWeek'],
      ),
      ageDay: getKeyValue(
        patientData,
        ['AgeDay'],
      ),
      medicalHistory: getKeyValue(
        patientData,
        ['MedicalHistory'],
      ),
      examiningPhysician: getKeyValue(
        patientData,
        ['ExaminingPhysician'],
      ),
    );
  }

  @override
  List<DataItemDTO>? convertPatientInfoToPatientDatas(
      PatientInfo? patientInfo) {
    if (patientInfo == null) {
      return [];
    }
    return [
      if (patientInfo.phone.isNotNullOrEmpty)
        DataItemDTO(
          key: 'Phone',
          value: FEncryptHelper.encodeBase64(
            patientInfo.phone ?? '',
          ),
        ),
      if (patientInfo.ageUnits.isNotNullOrEmpty)
        DataItemDTO(
          key: 'AgeUnits',
          value: patientInfo.ageUnits ?? 'Year',
        ),
      if (patientInfo.ageMonth.isNotNullOrEmpty)
        DataItemDTO(
          key: 'AgeMonth',
          value: patientInfo.ageMonth,
        ),
      if (patientInfo.ageWeek.isNotNullOrEmpty)
        DataItemDTO(
          key: 'AgeWeek',
          value: patientInfo.ageWeek,
        ),
      if (patientInfo.ageDay.isNotNullOrEmpty)
        DataItemDTO(
          key: 'AgeDay',
          value: patientInfo.ageDay,
        ),
      if (patientInfo.sex.isNotNullOrEmpty)
        DataItemDTO(
          key: 'Sex',
          value: patientInfo.sex,
        ),
      if (patientInfo.anamnesis.isNotNullOrEmpty)
        DataItemDTO(
          key: 'Anamnesis',
          value: patientInfo.anamnesis,
        ),
      if (patientInfo.ageYear.isNotNullOrEmpty)
        DataItemDTO(
          key: 'AgeYear',
          value: patientInfo.ageYear,
        ),
      if (patientInfo.name.isNotNullOrEmpty)
        DataItemDTO(
          key: 'Name',
          value: FEncryptHelper.encodeBase64(patientInfo.name ?? ''),
        ),
      if (patientInfo.identityCard.isNotNullOrEmpty)
        DataItemDTO(
          key: 'IdentityCard',
          value: FEncryptHelper.encodeBase64(patientInfo.identityCard ?? ''),
        ),
      if (patientInfo.examiningPhysician.isNotNullOrEmpty)
        DataItemDTO(
          key: 'ExaminingPhysician',
          value: patientInfo.examiningPhysician,
        ),
      if (patientInfo.medicalHistory.isNotNullOrEmpty)
        DataItemDTO(
          key: 'MedicalHistory',
          value: patientInfo.medicalHistory,
        ),
    ];
  }

  /// 根据后端接口的key值取到对应的value
  ///
  /// [patientData] 后端数据
  ///
  /// [keys] 对应的Key值
  @override
  String getKeyValue(
    List<DataItemDTO> patientData,
    List<String> keys,
  ) {
    return patientData.firstWhereOrNull((element) {
          return keys.contains(element.key);
        })?.value ??
        '';
  }

  @override
  Future<ClientPatientInfoDTO> findPatientByCode(
    String patientCode,
  ) async {
    return await rpc.patient.findPatientByCodeAsync(
      FindPatientByCodeRequest(
        code: patientCode,
        token: token,
      ),
    );
  }

  @override
  Future<List<FSelectModel>> findScanPositions() async {
    List<FSelectModel> scanPositionsList = [];
    try {
      final result = await rpc.liveConsultation.findScanPositionsAsync(
        TokenRequest(
          token: token,
        ),
      );

      for (int i = 0; i < result.length; i++) {
        scanPositionsList.add(
          FSelectModel(
            name: languageService.findLanguageValueByCode(
              'consultation',
              result[i],
            ),
            code: result[i],
          ),
        );
      }
    } catch (e) {
      printError(info: "getPersonDeviceDropdownListAsync exception:$e");
    }
    return scanPositionsList;
  }

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

    return result;
  }

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

  ///查询检查详情
  @override
  Future<QueryRecordResult?> queryRecordInfoAsync(String recordCode) async {
    try {
      return await rpc.recordInfo.queryRecordInfoAsync(
        QueryRecordRequest(
          token: Store.user.token,
          recordCode: recordCode,
        ),
      );
    } catch (e) {
      print('error:$recordCode');
      logger.i('queryRecordInfoAsync recordCode:$recordCode');
      logger.e('RemedicalManager queryRecordInfoAsync ex:', e);
      return null;
    }
  }

  @override
  Future<List<RemedicalAISelectedInfoDTO>> findAIImages(
      String recordCode, String patientId) async {
    final result = await rpc.remedical.getPatientAISelectedInfosAsync(
      GetPatientAISelectedInfosRequest(
        token: token,
        recordCode: recordCode,
        patientCode: patientId,
      ),
    );
    return result;
  }

  @override
  bool checkCarotidList(
      RemedicalItemList remedicalItem, CarotidScanTypeEnum scanTypeEnum) {
    return (remedicalItem.remedicalList
                ?.where(
                  (element) =>
                      element.carotidResult != null &&
                      element.carotidResult?.carotidScanType == scanTypeEnum,
                )
                .toList() ??
            [])
        .isNotEmpty;
  }

  @override
  Future<RemedicalInfoDTO> findRemedicalByCode(String remedicalCode) async {
    return rpc.remedical.findRemedicalByCodeAsync(
      FindRemedicalByCodeRequest(
        remedicalCode: remedicalCode,
        token: token,
      ),
    );
  }

  void openImageMeasurePage(
    String imageUrl,
    int imageindex,
    String remedicalCode,
    String recordCode,
    String? remedicalAISelectedInfoCode,
    String patientCode,
  ) {
    if (FPlatform.isWindows || FPlatform.isMacOS) {
      //如果是windows或者macos系统
      if (LocalSetting.ins.isUseSecondWindow! &&
          !CartSystemPlatform.isCartSystemVersion) {
        //如果是使用二级窗口，通知壳子，在第二窗口打开视频
        /// TODO 新增remedicalAISelectedInfoCode
        rpc.platform.openImageMeasureAsync(
            token, patientCode, remedicalCode, recordCode);
      } else {
        _openLocalMeasurePage(
          patientCode,
          remedicalCode,
          recordCode,
          remedicalAISelectedInfoCode ?? '',
        );
        var controller = Get.find<HomeController>();
        controller.state.currentRouter = RouteNames.Remedical.Measure;
      }
    } else {
      final url = html.window.location.origin;
      if (Store.app.enableNewTab) {
        var languageCode = i18nBook.locale.toCodeString("-");
        html.window.open(
            '$url/index.html?page=measure&token=$token&patientCode=$patientCode&remedicalCode=$remedicalCode&recordCode=$recordCode&lagCode=$languageCode&remedicalAISelectedInfoCode=$remedicalAISelectedInfoCode',
            '');
      } else {
        _openLocalMeasurePage(
          patientCode,
          remedicalCode,
          recordCode,
          remedicalAISelectedInfoCode ?? '',
        );
        var controller = Get.find<HomeController>();
        controller.state.currentRouter = RouteNames.Remedical.Measure;
      }
    }
  }

  @override
  Future<PageResult<SimpleRecordInfoDTO>> findRecordPages({
    List<String>? organizationCodes,
    List<String>? deviceCodes,
    RecordQueryStateEnum recordQueryState = RecordQueryStateEnum.All,
    RecordProcessStateEnum recordProcessState = RecordProcessStateEnum.All,
    String? keyWord,
    DateTime? startTime,
    DateTime? endTime,
    String? patientCode,
    int pageIndex = 1,
    int pageSize = 20,
  }) async {
    return await rpc.recordInfo.findRecordPagesAsync(
      FindRecordPagesRequest(
        token: Store.user.token,
        pageIndex: pageIndex,
        pageSize: pageSize,
        organizationCodes: organizationCodes,
        deviceCodes: deviceCodes,
        keyWord: keyWord,
        recordQueryState: recordQueryState,
        language: i18nBook.locale.toCodeString('-'),
        recordProcessState: recordProcessState,
        patientCode: patientCode,
        startTime: UtcDateConverter.getDayStartOrEndUTCTime(startTime),
        endTime: UtcDateConverter.getDayStartOrEndUTCTime(endTime, isEnd: true),
      ),
    );
  }

  void _openLocalMeasurePage(
    String patientCode,
    String remedicalCode,
    String recordCode,
    String remedicalAISelectedInfoCode,
  ) {
    var parasmeters = {
      "page": "measure",
      "patientCode": patientCode,
      "remedicalCode": remedicalCode,
      "recordCode": recordCode,
      "token": Store.user.token,
      "remedicalAISelectedInfoCode": remedicalAISelectedInfoCode,
    };
    router.to(
      RouteNames.Remedical.Measure,
      id: NavIds.HOME,
      parameters: parasmeters,
    );
  }
}
