import 'dart:async';

import 'package:fis_common/helpers/encrypt.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_ui/index.dart';
import 'package:fis_ui/interface/interactive_container.dart';
import 'package:flyinsono/architecture/services/modules/patient_configurations.dart';
import 'package:flyinsono/managers/interfaces/entities/patient_Info.dart';
import 'package:flyinsono/pages/remedical/consultation/controller.dart';
import 'package:flyinsono/pages/remedical/consultation/state.dart';
import 'package:flyinsono/pages/remedical/consultation/widgets/muti_select.dart';
import 'package:flyinsono/pages/remedical/index.dart';
import 'package:flyinsono/architecture/define.dart';
import 'package:flyinsono/architecture/services/modules/config_language.dart';
import 'package:flyinsono/architecture/states/states.dart';
import 'package:flyinsono/architecture/utils/prompt_box.dart';
import 'package:flyinsono/pages/remedical/consultation/widgets/patient_bind_mobile.dart';
import 'package:flyinsono/rpc.dart';
import 'package:get/get.dart';

/// 病人信息的控制器
class PatientInfoController extends FControllerBase {
  late ConsultationController controller;
  late FConsultationState state;

  /// 病人类型 人或宠物
  OrganizationPatientTypeEnum patientType = OrganizationPatientTypeEnum.Person;

  /// 组织名称
  String organizationName = '';

  /// 后台语言包控制器
  final languageService = Get.find<LanguageService>();

  /// 病人检查 配置项表单控制器
  final patient = Get.find<PatientCheckService>();

  ///病人页面一页长度
  final int pageSize = 10;

  /// 当前可滑动的最大下标
  int maxIndex = 0;
  PatientInfoController(ConsultationController controller) {
    this.controller = controller;
    this.state = controller.state;
  }

  /// 编辑病人信息
  void editPatient(PatientInfo patientInfo) async {
    final patientInfoController = Get.put(AddoreditPatientDialogController());
    patientInfoController.openEditInit(
      patientInfo.patientCode,
    );
    patientInfoController.editPatientInfo = {};
  }

  /// 手机端绑定病人页面
  void openBindPatient({String? patientCode, String? phone}) async {
    state.associatPatientInfos = [];
    state.setValidPatientRequest = SetValidPatientRequest();
    await Get.to(
      () => BindPatient(
        patientCode: patientCode,
        phone: phone,
      ),
    );
  }

  /// 删除病人接口
  void deletePatient(String patientCode, FInteractiveContainer businessParent) {
    FConfirmAlert.show(
      businessParent: businessParent,
      context: Get.context!,
      title: i18nBook.common.tip.t,
      subTitle: i18nBook.remedical.removePatientConfirm.t,
      confrimLabel: i18nBook.common.confirm.t,
      cancelLabel: i18nBook.common.cancel.t,
      onConfirm: () async {
        await busyHandle(
          () async {
            final removePatientsAsync = await rpc.patient.removePatientsAsync(
              RemovePatientsRequest(
                token: Store.user.token,
                patientCodes: [patientCode],
              ),
            );
            if (removePatientsAsync) {
              await controller.refersh().then(
                    (value) => PromptBox.toast(
                      i18nBook.remedical.deletePatientSuccess.t,
                    ),
                  );
            } else {
              PromptBox.toast(i18nBook.remedical.deleteFailed.t);
            }
          },
          text: i18nBook.remedical.deleting.t,
        );
      },
    );
  }

  /// 病人数据处理
  void dataHandle<T extends ClientPatientInfoBaseDTO>(
    PageResult<T> patients,
    bool? isDropUp,
    bool isChange,
  ) {
    List<PatientInfo> patientInfos = [];
    final count = patients.totalCount / 10;
    state.listTotalCount = patients.totalCount;
    maxIndex = patients.totalCount % 10 == 0
        ? count.toInt()
        : patients.totalCount ~/ 10 + 1;
    if (patients.pageData != null) {
      patients.pageData!.forEach(
        (element) {
          var name =
              getKeyValue(element.patientData!, ['Name', 'AnimalInfoName']);
          var phone =
              getKeyValue(element.patientData!, ['Phone', 'AnimalInfoPhone']);
          var id = getKeyValue(
            element.patientData!,
            ['IdentityCard', 'AnimalInfoIdentityCard'],
          );
          var insuranceCode =
              getKeyValue(element.patientData!, ['InsuranceCode']);
          String? code;
          String? outUserName;
          String? inUserName;
          if (element is QueryReferralRecordPageDTO) {
            code = element.code;
            outUserName = element.outUserName;
            inUserName = element.inUserName;
          }
          patientInfos.add(
            PatientInfo(
              patientCode: element.patientCode!,
              referralRecordCode: code ?? '',
              isValid: element.isValid,
              isReferral: element.isReferral,
              organizationName: element.organizationName,
              name: name,
              phone: phone,
              identityCard: id,
              insuranceCode: insuranceCode,
              age: getKeyValue(
                element.patientData!,
                ['Age', 'AnimalInfoAge'],
              ),
              sex: getKeyValue(
                element.patientData!,
                ['Sex', 'AnimalInfoSex'],
              ),
              species: getKeyValue(
                element.patientData!,
                ['Species'],
              ),
              breed: getKeyValue(
                element.patientData!,
                ['Breed'],
              ),
              headImgUrl: getKeyValue(
                element.patientData!,
                ['HeadImgUrl', 'AnimalInfoHeadImgUrl'],
              ),
              birthday: getKeyValue(
                element.patientData!,
                ['Birthday'],
              ),
              ageUnits: getKeyValue(
                element.patientData!,
                ['AgeUnits'],
              ),
              ageYear: getKeyValue(
                element.patientData!,
                ['AgeYear'],
              ),
              ageMonth: getKeyValue(
                element.patientData!,
                ['AgeMonth'],
              ),
              ageWeek: getKeyValue(
                element.patientData!,
                ['AgeWeek'],
              ),
              ageDay: getKeyValue(
                element.patientData!,
                ['AgeDay'],
              ),
              inUserName: inUserName ?? '',
              outUserName: outUserName ?? '',
            ),
          );
        },
      );
    }

    /// 下拉数据接口请求
    if (isDropUp ?? false) {
      state.patientInfos = patientInfos;
      state.patientPageInt = 1;
    } else {
      state.patientInfos = [...state.patientInfos, ...patientInfos];
    }

    /// 初始化 改动病人信息
    if (state.patientInfos.length > 0) {
      if (!isChange) {
        state.selectPatientCardIndex = 0;
        state.patientCode = state.patientInfos[0].patientCode;
        state.isShowValid = state.patientInfos[0].isValid;
        controller.clickPatientCard(
          state.selectPatientCardIndex,
          state.patientInfos[0],
        );

        /// 判断是否是有转诊病人的code
        if (state.patientTab == 1) {
          state.referralRecordCode = state.patientInfos[0].referralRecordCode;
        }
      }
    } else {
      state.patientCode = '';
      state.referralRecordCode = '';
      busy = false;
    }
    state.updateSelectAllState();
  }

  /// 手机端头像第一个字  avatar = widget.patientInfo!['name'].toString().substring(0, 1);
  String getAvatar(String? name) {
    String getAvatar = name.toString().substring(0, 1);
    return getAvatar;
  }

  /// 设备端快捷创建病人
  ///
  /// [value] 关联病人时精确搜索找不到病人就快捷创建病人
  String capitalize(String value) {
    if (value.trim().isEmpty) return "";
    return "${value[0].toUpperCase()}${value.substring(1)}";
  }

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

  Future<ClientPatientInfoDTO> findPatientByCodeAsync(
      [String? patientCode]) async {
    try {
      final patients = await rpc.patient.findPatientByCodeAsync(
        FindPatientByCodeRequest(
          code: patientCode != null ? patientCode : state.patientCode,
          token: Store.user.token,
        ),
      );
      return patients;
    } catch (e) {
      return ClientPatientInfoDTO();
    }
  }

  ///获取病人信息
  Future<void> getPatientInfo([String? patientCode]) async {
    try {
      final patients = state.patientTab == 0
          ? await findPatientByCodeAsync(patientCode)
          : await controller.referPatientInfoController
              .queryReferralPatientByCodeAsync(patientCode);
      if (patients.lastRecord != null) {
        state.lastRecord = patients.lastRecord!;
      }
    } catch (e) {
      printError(info: "findPatientByCodeAsync exception:" + e.toString());
      logger.e("findPatientByCodeAsync exception:", e);
      state.lastRecord = GetRecordsPageDTO();
    }
  }

  /// 关联时获取信息
  Future<String> getAssociatPatientInfo([String? patientCode]) async {
    busy = true;
    final patients = state.patientTab == 0
        ? await findPatientByCodeAsync(patientCode)
        : await controller.referPatientInfoController
            .queryReferralPatientByCodeAsync(patientCode);

    busy = false;
    if (patients.lastRecord != null) {
      patients.lastRecord!.creatorName =
          FEncryptHelper.decryptBase64(patients.lastRecord!.creatorName ?? '');
    }
    return patients.lastRecord?.recordCode ?? '';
  }

  /// 关联病人的列表
  Future<void> getAssociatPatients(
    FInteractiveContainer businessParent,
  ) async {
    if (state.patientName.isEmpty) {
      PromptBox.toast(i18nBook.remedical.patientNamePlaceholder.t);
    } else {
      try {
        final patients = await rpc.patient.findValidPatientsByNameAsync(
          FindValidPatientsByNameRequest(
            token: Store.user.token,
            name: FEncryptHelper.encodeBase64(state.patientName),
          ),
        );
        List<Map<String, dynamic>> patientInfos = [];
        if (patients.length != 0) {
          patients.forEach(
            (element) {
              var name = element.patientData!
                      .firstWhereOrNull(
                        (element) =>
                            element.key == "Name" ||
                            element.key == "AnimalInfoName",
                      )
                      ?.value ??
                  "";
              var phone = element.patientData!
                      .firstWhereOrNull(
                        (element) =>
                            element.key == "Phone" ||
                            element.key == "AnimalInfoPhone",
                      )
                      ?.value ??
                  "";
              patientInfos.add(
                {
                  'patientCode': element.patientCode,
                  'name': name,
                  'phone': phone,
                  'headImgUrl': element.patientData!
                          .firstWhereOrNull(
                            (element) =>
                                element.key == "HeadImgUrl" ||
                                element.key == "AnimalInfoHeadImgUrl",
                          )
                          ?.value ??
                      "",
                },
              );
            },
          );
          state.associatPatientInfos = patientInfos;
        } else {
          FConfirmAlert.show(
            businessParent: businessParent,
            context: Get.context!,
            title: i18nBook.common.tip.t,
            subTitle: i18nBook.remedical.hint4patientNotFound.translate(
              [state.patientName],
            ),
            confrimLabel: i18nBook.common.confirm.t,
            cancelLabel: i18nBook.common.cancel.t,
            onConfirm: () async {
              await busyHandle(
                () async {
                  final name = FEncryptHelper.encodeBase64(state.patientName);
                  await createPatientByUnregisteredAsync(
                    state.patient!.patientCode,
                    name,
                  );
                  getAssociatPatients(businessParent);
                },
                text: i18nBook.remedical.creating.t,
              );
            },
          );
        }
      } catch (e) {
        printError(info: "getPatients exception:" + e.toString());
        logger.e("getPatients exception:", e);
      }
    }
  }

  Future<void> getOrganizationByUserAndDevicesAsync() async {
    try {
      final result =
          await rpc.organization.getOrganizationByUserAndDevicesAsync(
        GetOrganizationByUserAndDevicesRequest(
          token: Store.user.token,
          pageIndex: 1,
          pageSize: 100,
        ),
      );
      List<FMutiSelectModel> _organizationLocatedList = [];
      for (OrganizationSimplifyDTO i in result.pageData ?? []) {
        _organizationLocatedList.add(
          FMutiSelectModel(
            code: i.organizationCode!,
            name: i.organizationName!,
          ),
        );
      }
      state.organizationLocatedList = _organizationLocatedList;
    } catch (e) {
      printError(
          info:
              "getOrganizationByUserAndDevicesAsync exception:" + e.toString());
      logger.e("getOrganizationByUserAndDevicesAsync exception:", e);
    }
  }

  Future<void> getPersonDeviceDropdownPageAsync() async {
    try {
      final result = await rpc.device.getPersonDeviceDropdownPageAsync(
        GetPersonDeviceDropdownPageRequest(
          token: Store.user.token,
          pageIndex: 1,
          pageSize: 100,
          restrictOrgCodes: state.selectedOrganizationLocated,
        ),
      );
      List<FMutiSelectModel> _personDeviceList = [];
      for (SelectItemDTO i in result.pageData ?? []) {
        _personDeviceList.add(
          FMutiSelectModel(
            code: i.key!,
            name: i.value!,
          ),
        );
      }
      state.personDeviceList = _personDeviceList;
    } catch (e) {
      printError(
          info: "getPersonDeviceDropdownPageAsync exception:" + e.toString());
      logger.e("getPersonDeviceDropdownPageAsync exception:", e);
    }
  }

  /// 未登记关联创建病人
  Future<void> createPatientByUnregisteredAsync(
    String unregisteredPatientCode,
    String patientName,
  ) async {
    try {
      busy = true;
      final result = await rpc.patient.createPatientByUnregisteredAsync(
        CreatePatientByUnregisteredRequest(
          token: Store.user.token,
          unregisteredPatientCode: unregisteredPatientCode,
          patientName: patientName,
        ),
      );
      if (!result) {
        PromptBox.toast(i18nBook.remedical.creatFailed.t);
      }
      busy = false;
    } catch (e) {
      printError(
          info: "createPatientByUnregisteredAsync exception:" + e.toString());
      logger.e("createPatientByUnregisteredAsync exception:", e);
      busy = false;
    }
  }

  /// 我的病人列表
  Future<PageResult<ClientPatientInfoBaseDTO>> findPatientsAsync(bool? isDropUp,
      {int size = 10, String? parameterPatientCode}) async {
    try {
      final patients = await rpc.patient.findPatientsAsync(
        FindPatientsPageRequest(
          token: Store.user.token,
          pageIndex: isDropUp! ? 1 : state.patientPageInt,
          pageSize: size,
          keyWord: state.keyWord,
          startTime: state.startDateTime,
          patientCode: state.parameterPatientCode,
          endTime: state.endDateTime,
          organizationCodes: state.selectedOrganizationLocated,
          deviceCodes: state.selectedpersonDevice,
          isValid: state.isValid == 0
              ? PatientValidStatusEnum.All
              : state.isValid == 1
                  ? PatientValidStatusEnum.CheckOut
                  : PatientValidStatusEnum.CheckIn,
        ),
      );
      return patients;
    } catch (e) {
      logger.e('PatientInfoController findPatientsAsync', e);
      return PageResult<ClientPatientInfoBaseDTO>();
    }
  }

  /// 获取病人列表
  ///
  /// [isDropUp] 是否刷新数据 非下拉数据
  ///
  /// [isChange] 可选 是否改变病人code
  Future<void> getPatients(
    bool? isDropUp, [
    bool isChange = false,
    int pageSize = 10,
  ]) async {
    try {
      final PageResult<ClientPatientInfoBaseDTO> patients =
          await findPatientsAsync(
        isDropUp,
        size: pageSize,
      );
      dataHandle(patients, isDropUp, isChange);
    } catch (e) {
      busy = false;
      printError(info: "getPatients exception:" + e.toString());
      logger.e("getPatients exception:", e);
    }
  }

  /// 关联病人- 保存按钮
  ///
  /// [setValidPatientRequest] 保存病人信息
  Future<void> setVaildPatient(
    SetValidPatientRequest setValidPatientRequest,
  ) async {
    if (setValidPatientRequest.newPatientCode == null) {
      PromptBox.toast(i18nBook.remedical.selectPatientToAssociate.t);
    } else {
      // router.dialog(
      //   () => AssociateExamsOperationDialog(
      //     setValidPatientRequest: setValidPatientRequest,
      //   ),
      // );
      /// 直接迁移图像
      controller.inspectionRecordsController.association(
        setValidPatientRequest.newPatientCode!,
        setValidPatientRequest.oldPatientCode!,
      );
    }
  }

  /// 翻译
  String getValues(String code) {
    try {
      var value = languageService.findLanguageValueByCode('exam', code);
      return value;
    } catch (e) {
      print(e);
    }
    return code;
  }

  /// 获取组织信息
  Future<void> getOrgType() async {
    try {
      final result = await rpc.user.getUserInfoAsync(
        GetUserInfoRequest(token: Store.user.token),
      );
      if (result.rootOrganizationCode?.isNotEmpty ?? false) {
        final org = await rpc.organization.getOrganizationByCodeAsync(
          GetOrganizationByCodeRequest(
            organizationCode: result.rootOrganizationCode,
            token: Store.user.token,
          ),
        );
        patientType = org.patientType;
        state.patientType = org.patientType;
        state.isSafeMode = org.isEncryptedShow;
        organizationName = org.organizationName ?? '';
      }
    } catch (e) {
      printError(info: "getOrgType exception:" + e.toString());
      logger.e("getOrgType exception:", e);
    }
  }
}
