import 'dart:convert';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:uuid/uuid.dart';
import 'package:vitalapp/architecture/utils/prompt_box.dart';
import 'package:vitalapp/components/alert_dialog.dart';
import 'package:vitalapp/database/db.dart';
import 'package:vitalapp/database/entities/defines.dart';
import 'package:vitalapp/database/entities/diagnosis.dart';
import 'package:vitalapp/global.dart';
import 'package:vitalapp/managers/interfaces/patient.dart';
import 'package:vitalapp/managers/interfaces/record_data_cache.dart';
import 'package:vnote_device_plugin/consts/types.dart';
import 'package:vitalapp/architecture/defines.dart';
import 'package:vitalapp/architecture/storage/text_storage.dart';
import 'package:vitalapp/managers/interfaces/cachedRecord.dart';
import 'package:vitalapp/managers/interfaces/device.dart';
import 'package:vitalapp/managers/interfaces/diagnosis.dart';
import 'package:vitalapp/managers/interfaces/models/device.dart';
import 'package:vitalapp/pages/medical/models/item.dart';
import 'package:vitalapp/pages/medical/state.dart';
import 'package:vitalapp/store/store.dart';
import 'package:vnote_device_plugin/events/event_type.dart';
import 'package:fis_common/logger/logger.dart';

class MedicalController extends FControllerBase {
  String patientCode = '';
  Map<String, dynamic> diagnosisDataValue = {};
  final _patientManager = Get.find<IPatientManager>();
  String appDataId = "";
  final state = MedicalState();
  final recordDataCacheManager = Get.find<IRecordDataCacheManager>();
  static final typeConvertMap = <String, String>{
    DeviceTypes.TEMP: "Temp",
    DeviceTypes.WEIGHT: "BMI",
    DeviceTypes.SPO2: "SpO2",
    DeviceTypes.NIBP: "NIBP",
    DeviceTypes.SUGAR: "GLU",
    DeviceTypes.URINE: "Urine",
    DeviceTypes.IC_READER: "ICReader",
    DeviceTypes.HEART: "HEART",
    DeviceTypes.TWELVEHEART: "Twelveheart",
  };

  final changePatient = FEventHandler<String>();
  final _diagnosisManager = Get.find<IDiagnosisManager>();
  final _cachedRecordManager = Get.find<ICachedRecordManager>();
  final _deviceManager = Get.find<IDeviceManager>();
  final _medicalMenus = [
    MedicalItem(key: DeviceTypes.TEMP, diagnosticItem: '体温'),
    MedicalItem(key: DeviceTypes.SUGAR, diagnosticItem: '血糖'),
    MedicalItem(key: DeviceTypes.NIBP, diagnosticItem: '血压'),
    MedicalItem(key: DeviceTypes.SPO2, diagnosticItem: '血氧'),
    MedicalItem(key: DeviceTypes.WEIGHT, diagnosticItem: 'BMI'),
    MedicalItem(key: DeviceTypes.WAIST, diagnosticItem: '腰臀比'),
    MedicalItem(key: DeviceTypes.URINE, diagnosticItem: '尿常规'),
    MedicalItem(key: DeviceTypes.HEART, diagnosticItem: '心电'),
    MedicalItem(key: DeviceTypes.TWELVEHEART, diagnosticItem: '十二导心电'),
  ];
  @override
  void onInit() async {
    setBusy('Loading...');
    await initData();
    await getAccessTypes();
    state.currentTab = DeviceTypes.TEMP; //等数据加载完成之后在切换到体温页面
    busy = false;
    logger.i('MedicalController init end');
    super.onInit();
  }

  Future<void> initData() async {
    patientCode = Store.user.currentSelectPatientInfo?.code ?? '';
    if (patientCode.isNotEmpty) {
      logger.i(
          'MedicalController initData  patientName:${Store.user.currentSelectPatientInfo?.patientName} patientCode:${Store.user.currentSelectPatientInfo?.code}');
      var cachedAppDataId = await readCachedAppDataId();
      if (cachedAppDataId != null) {
        appDataId = cachedAppDataId;
      } else {
        await saveCachedAppDataId();
      }
      await initReadCached();
    }
  }

  Future<void> getAccessTypes() async {
    List<MedicalItem> medicalItemList = [];
    List<String> accessTypes = await _deviceManager.getAccessTypes();
    for (var element in _medicalMenus) {
      if (accessTypes.contains(element.key)) {
        medicalItemList.add(element);
      }
    }
    state.medicalMenuList = medicalItemList;
  }

  Future<DeviceModel?> getDevice(String type) async {
    List<DeviceModel> devices = await _deviceManager.getDeviceList();
    return devices.firstWhereOrNull((element) => element.type == type);
  }

  Future<void> initReadCached() async {
    if (patientCode.isNotEmpty) {
      logger
          .i('MedicalController initReadCached fail，patientCod e：$patientCode');
      TextStorage cachedRecord = TextStorage(
        fileName: 'JKJC',
        directory: "patient/$patientCode",
      );
      String? value = await cachedRecord.read();
      if (value == null) {
        diagnosisDataValue = {};
        Store.resident.handleSaveMedicalData(jsonEncode(diagnosisDataValue));
        return;
      }
      Store.resident.handleSaveMedicalData(value);
      diagnosisDataValue = jsonDecode(value);
    }
  }

  Future<bool?> saveCachedAppDataId() async {
    appDataId = const Uuid().v4().replaceAll('-', '');
    TextStorage cachedRecord = TextStorage(
      fileName: 'appDataId',
      directory: "patient/$patientCode",
    );
    Get.back();
    return cachedRecord.save(appDataId);
  }

  Future<String?> readCachedAppDataId() async {
    TextStorage cachedRecord = TextStorage(
      fileName: 'appDataId',
      directory: "patient/$patientCode",
    );
    return cachedRecord.read();
  }

  Future<bool?> saveCachedRecord() async {
    if (patientCode.isEmpty) {
      logger.i(
          'MedicalController saveCachedRecord fail，patientCode：$patientCode');
      return false;
    }
    Store.resident.handleSaveMedicalData(jsonEncode(diagnosisDataValue));
    TextStorage cachedRecord = TextStorage(
      fileName: 'JKJC',
      directory: "patient/$patientCode",
    );
    return cachedRecord.save(jsonEncode(diagnosisDataValue));
  }

  Future<bool?> deleteDirectory() async {
    TextStorage cachedRecord = TextStorage(
      fileName: 'JKJC',
      directory: "patient/$patientCode",
    );
    return cachedRecord.deleteDirectory();
  }

  Future<void> submitDiagnosis(
    Map<String, dynamic> submitDiagnosisDataValue,
  ) async {
    try {
      List<DiagnosisItem> diagnosisItems = await recordDataCacheManager
          .verifyDiagnosisDataList(submitDiagnosisDataValue);

      state.currentTab = '-1';
      await recordDataCacheManager.saveRecordData(
        appDataId,
        patientCode,
        submitDiagnosisDataValue,
      );
      if (kIsOnline) {
        busy = true;
        diagnosisItems = await recordDataCacheManager
            .convertDiagnosisDataToList(submitDiagnosisDataValue);
        bool result;
        result = await _diagnosisManager.syncPatientAndDiagnosisData(
          SyncPatientAndDiagnosisDataRequest(
            patientCode: patientCode,
            patientName: Store.user.currentSelectPatientInfo?.patientName ?? '',
            patientAddress:
                Store.user.currentSelectPatientInfo?.patientAddress ?? '',
            patientGender: Store.user.currentSelectPatientInfo?.patientGender ??
                GenderEnum.Unknown,
            permanentResidenceAddress:
                Store.user.currentSelectPatientInfo?.permanentResidenceAddress,
            phone: Store.user.currentSelectPatientInfo?.phone,
            cardNo: Store.user.currentSelectPatientInfo?.cardNo,
            nationality: Store.user.currentSelectPatientInfo?.nationality,
            birthday: Store.user.currentSelectPatientInfo?.birthday,
            crowdLabels: Store.user.currentSelectPatientInfo?.crowdLabels,
            cardType: Store.user.currentSelectPatientInfo?.cardType ??
                CardTypeEnum.Identity,
            contractedDoctor:
                Store.user.currentSelectPatientInfo?.contractedDoctor,
            appDataId: appDataId,
            diagnosisTime: DateTime.now(),
            token: Store.user.token,
            diagnosisItems: diagnosisItems,
          ),
        );
        busy = false;
        if (result) {
          //如果在线，则提交历史数据
          var submitSuccess = await _submitHistory();
          if (submitSuccess) {
            logger.i('当前数据提交成功，且历史记录：$patientCode 提交成功');
          }
          recordDataCacheManager.recordSyncStateChange(appDataId);
          PromptBox.toast('提交成功');
          await initRecordDataState();

          ///提交之后，测试结果清空
          diagnosisDataValue.clear();
        } else {
          PromptBox.toast('提交失败');
          logger.i('提交失败：$patientCode');
        }
        state.currentTab = state.medicalMenuList[0].key;
      } else {
        Future.delayed(const Duration(milliseconds: 10), () {
          state.currentTab = state.medicalMenuList[0].key;
        });
        PromptBox.toast("已缓存至本地");
        logger.i('已缓存至本地：$patientCode');
        await initRecordDataState();

        ///提交之后，测试结果清空
        diagnosisDataValue.clear();
        state.currentTab = state.medicalMenuList[0].key;

        Get.back();
      }
    } catch (err) {
      busy = false;
      state.currentTab = state.medicalMenuList[0].key;
      logger.e('submitDiagnosis error: ${err.toString()}');
    }
  }

  Future<void> initRecordDataState() async {
    await saveCachedAppDataId();
    await deleteDirectory();
    await initReadCached();
  }

  Future<void> createDiagnosis() async {
    busy = true;
    try {
      if (Store.user.teamName.isEmpty) {
        PromptBox.toast('未设置团队无法提交检测数据');
        return;
      }
      if (patientCode.isEmpty ||
          patientCode != Store.user.currentSelectPatientInfo?.code) {
        initData();
      }
      Map<String, dynamic> submitDiagnosisDataValue =
          Map.from(diagnosisDataValue); //确定提交值不会发生变更

      List<DiagnosisItem> diagnosisItems = await recordDataCacheManager
          .verifyDiagnosisDataList(submitDiagnosisDataValue);
      logger.i('submitDiagnosis diagnosisItems.leng:${diagnosisItems.length}');
      if (diagnosisItems.isEmpty) {
        if (patientCode.isNotEmpty && kIsOnline) {
          bool submitHistory = await _submitHistory();
          if (submitHistory) {
            PromptBox.toast('提交成功');
            return;
          }
        }
        PromptBox.toast('不能提交空数据');
        return;
      }
      if (state.medicalMenuList.length > submitDiagnosisDataValue.length) {
        logger.i(
            'state.medicalMenuList.length：${state.medicalMenuList.length},copiedDiagnosisDataValue.length：${diagnosisDataValue.length}');
        Get.dialog(
          VAlertDialog(
            title: '提示',
            content: Container(
              margin: const EdgeInsets.only(bottom: 20),
              child: const Text(
                '当前检测项目未完成，请确定是否提交本次检测',
                style: TextStyle(fontSize: 20),
                textAlign: TextAlign.center,
              ),
            ),
            showCancel: true,
            onConfirm: () {
              Get.back();
              submitDiagnosis(submitDiagnosisDataValue);
            },
            onCanceled: () {},
          ),
        );
        return;
      } else {
        ///如果已完成所有检查，则直接提交
        submitDiagnosis(submitDiagnosisDataValue);
      }
    } catch (e) {
      logger.e('MedicalController createDiagnosis ex:', e);
    } finally {
      busy = false;
    }
  }

  @override
  void dispose() {
    print('MedicalController dispose');
    super.dispose();
  }

  ///提交历史记录
  Future<bool> _submitHistory() async {
    var existDatas =
        await recordDataCacheManager.getNoSubmitRecords(patientCode);
    var historyDatas = existDatas.where((element) => element.code != appDataId);
    if (historyDatas.isEmpty) {
      return false;
    }

    for (DiagnosisEntity data in historyDatas) {
      try {
        Map<String, dynamic> jsonData = jsonDecode(data.dataJson);
        var diagnosisItems =
            await recordDataCacheManager.convertDiagnosisDataToList(jsonData);
        SubmitDiagnosisRequest submitDiagnosisRequest = SubmitDiagnosisRequest(
          appDataId: data.code,
          patientCode: data.patientCode,
          diagnosisItems: diagnosisItems,
          diagnosisTime: data.updateTime ?? data.createTime,
        );
        bool submitResult;
        if (kIsOnline) {
          PatientDTO? patientInfo = await _patientManager.getDetail(
            data.patientCode,
          );
          if (patientInfo == null) {
            ///如果Server没有，则从本地读取
            var patientEntity = await db.repositories.patient
                .singleByCode(data.patientCode, Store.user.userCode!);
            if (patientEntity != null) {
              patientInfo =
                  PatientDTO.fromJson(jsonDecode(patientEntity.dataJson));
            }
          }
          submitResult = await _diagnosisManager.syncPatientAndDiagnosisData(
            SyncPatientAndDiagnosisDataRequest(
              token: Store.user.token,
              patientCode: data.patientCode,
              patientName: patientInfo?.patientName ?? '',
              patientAddress: patientInfo?.patientAddress ?? '',
              patientGender: patientInfo?.patientGender ?? GenderEnum.Unknown,
              permanentResidenceAddress: patientInfo?.permanentResidenceAddress,
              phone: patientInfo?.phone,
              cardNo: patientInfo?.cardNo,
              nationality: patientInfo?.nationality,
              birthday: patientInfo?.birthday,
              crowdLabels: patientInfo?.crowdLabels,
              cardType: patientInfo?.cardType ?? CardTypeEnum.Identity,
              contractedDoctor: patientInfo?.contractedDoctor,
              appDataId: data.code,
              diagnosisTime: data.updateTime ?? data.createTime,
              diagnosisItems: diagnosisItems,
            ),
          );
        } else {
          submitResult = await _diagnosisManager
              .submitDiagnosisAsync(submitDiagnosisRequest);
        }
        OfflineDataSyncState state;
        if (submitResult) {
          state = OfflineDataSyncState.success;
          logger.i('提交历史记录：$patientCode 成功');
        } else {
          state = OfflineDataSyncState.fail;
          logger.i('提交历史记录：$patientCode 失败');
        }
        recordDataCacheManager.recordSyncStateChange(data.code, state: state);
      } catch (e) {
        logger.e('MedicalController _submitHistory ex:', e);
      }
    }
    return true;
  }
}
