import 'dart:convert';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:vital_local_database/core/interface/queryable.dart';
import 'package:vitalapp/database/db.dart';
import 'package:vitalapp/database/entities/defines.dart';
import 'package:vitalapp/database/entities/patient.dart';
import 'package:vitalapp/global.dart';
import 'package:vitalapp/managers/interfaces/models/patient_model_dto.dart';
import 'package:vitalapp/managers/interfaces/patient.dart';
import 'package:vitalapp/mock/services/patient.dart';
import 'package:vitalapp/rpc.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:vitalapp/store/store.dart';

class PatientManager implements IPatientManager {
  @override
  Future<String?> create(CreatePatientRequest request) async {
    request.token = Store.user.token;
    request.code = request.cardNo;
    final result = await rpc.patient.createPatientAsync(request);
    return result;
  }

  @override
  Future<List<PatientModelDTO>?> getPagedOfflineList(
      PatientPageRequest request) async {
    final entities = await db.repositories.patient.queryable
        .where((x) {
          final List<IDbColumnCondition> arr = [];
          arr.add(x.isValid.equals(true));
          arr.add(x.userCode.equals(Store.user.userCode)); //添加用户code
          arr.add(x.syncState.notEquals(OfflineDataSyncState.success));
          final keyword = request.keyword;
          if (keyword != null && keyword.isNotEmpty) {
            // TODO: 暂时只支持姓名模糊
            arr.add(x.name.like("%$keyword%' OR code like '%$keyword%"));
          } else {
            if (request.startTime != null) {
              arr.add(x.createTime.gte(request.startTime));
            }
            if (request.endTime != null) {
              arr.add(x.createTime.lt(request.endTime));
            }
          }
          return arr;
        })
        .orderBy((x) => x.createTime, DbOrderByType.desc)
        .toList();
    final dtos = entities.map((e) {
      var patientModel = PatientModelDTO.fromJson(jsonDecode(e.dataJson));
      patientModel.isExistLocalData = true;
      return patientModel;
    }).toList();
    return dtos;
  }

  @override
  Future<PatientDTO?> getDetail(String code) async {
    try {
      final request = GetPatientRequest(code: code, token: Store.user.token);
      if (kIsOnline) {
        //在线状态，先查询是否存在本体未提交数据
        final entity = await db.repositories.patient
            .singleByCode(code, Store.user.userCode!);
        if (entity != null &&
            entity.dataJson.isNotEmpty &&
            entity.syncState != OfflineDataSyncState.success) {
          logger.i("PatientManager query patient detail location exist.");
          final jsonMap = jsonDecode(entity.dataJson);
          final dto = PatientDTO.fromJson(jsonMap);
          return dto;
        } else {
          logger.i("PatientManager query patient detail location not exist.");
        }
      }
      final result = await rpc.patient.getPatientDetailAsync(request);
      return result;
    } catch (e) {
      logger.e("PatientManager query patient detail error.", e);
      return null;
    }
  }

  @override
  Future<PageCollection<PatientModelDTO>?> getPagedList(
      PatientPageRequest request) async {
    PageCollection<PatientModelDTO>? listPatientDto =
        PageCollection<PatientModelDTO>();
    try {
      request.token = Store.user.token;
      final result = await rpc.patient.getPatientPageAsync(request);
      listPatientDto.dataCount = result.dataCount;
      listPatientDto.pageData = [];
      for (var element in result.pageData!) {
        var patientModel = PatientModelDTO.fromJson(element.toJson());
        var isNotUploadedPatient = await db.repositories.patient
            .isNotUploadedPatient(element.code!, Store.user.userCode!);
        if (isNotUploadedPatient) {
          if (kIsOnline) {
            continue;
          } else {
            patientModel.isExistLocalData = true;
          }
        } else {
          final localCount = await db.repositories.diagnosis
              .getNotUploadedCountByPatientCode(
                  element.code!, Store.user.userCode!);
          if (localCount > 0) {
            patientModel.isExistLocalData = true;
          }
        }
        listPatientDto.pageData?.add(patientModel);
      }
      return listPatientDto;
    } catch (e) {
      logger.e("PatientManager query patient paged list error.", e);
      return null;
    }
  }

  @override
  Future<bool> updatePatientAsync(UpdatePatientRequest request) async {
    try {
      if (kIsOnline) {
        await _updateLocationPatientAsync(request);
      }
      final result = await rpc.patient.updatePatientAsync(request);
      return result;
    } catch (e) {
      return false;
    }
  }

  ///在线编辑居民信息时，同步更改本地缓存
  Future<bool> _updateLocationPatientAsync(UpdatePatientRequest request) async {
    final code = request.code!;
    final existEntity = await _checkPatientExist(code);

    PatientEntity entity;
    PatientDTO dto;
    if (existEntity == null) {
      entity = PatientEntity();
      entity.code = request.code!;
      entity.isValid = true;
      entity.name = request.patientName!;
      entity.userCode = Store.user.userCode!; //添加用户code
      entity.syncState = OfflineDataSyncState.success;
      dto = PatientDTO();
      ModelConverter.syncUpdate2Dto(dto, request);

      final dtoJson = dto.toJson();
      entity.dataJson = jsonEncode(dtoJson);

      final id = await db.repositories.patient.insert(entity);
      return id > 0;
    } else {
      entity = existEntity;
      final jsonMap = jsonDecode(entity.dataJson);
      dto = PatientDTO.fromJson(jsonMap);
      ModelConverter.syncUpdate2Dto(dto, request);

      final dtoJson = dto.toJson();
      entity.dataJson = jsonEncode(dtoJson);

      final rows = await db.repositories.patient.update(entity);
      return rows > 0;
    }
  }

  Future<PatientEntity?> _checkPatientExist(String code) async {
    try {
      final entity = await db.repositories.patient
          .singleByCode(code, Store.user.userCode!);
      return entity;
    } catch (e) {
      logger.e(
          "PatientServiceMock - Check patient exist error. Code: $code.", e);
    }
    return null;
  }

  @override
  Future<bool> setCrowdLabelsAsync(
      String patientCode, List<String> crowLabels) async {
    try {
      final request = SetCrowdLabelsRequest(
          code: patientCode, crowdLabels: crowLabels, token: Store.user.token);
      final result = rpc.patient.setCrowdLabelsAsync(request);
      return result;
    } catch (e) {
      return false;
    }
  }

  @override
  Future<String> createPatientExtensionAsync(
      CreatePatientExtensionRequest request) async {
    try {
      final result =
          await rpc.patientExtension.createPatientExtensionAsync(request);
      return result;
    } catch (e) {
      return '';
    }
  }

  @override
  Future<PatientExtensionDTO?> getPatientExtensionDetailByCodeAndKeyAsync(
      GetPatientExtensionByCodeAndKeyRequest request) async {
    try {
      final result = await rpc.patientExtension
          .getPatientExtensionDetailByCodeAndKeyAsync(request);
      return result;
    } catch (e) {
      return null;
    }
  }

  @override

  ///更新居民健康信息
  Future<bool> updatePatientExtensionAsync(
      UpdatePatientExtensionRequest request) async {
    try {
      final result =
          await rpc.patientExtension.updatePatientExtensionAsync(request);
      return result;
    } catch (e) {}
    return false;
  }

  ///获取所有userCode为空的数据，并赋值
  @override
  Future<void> resettingUsercodeIsEmptyData() async {
    var version = await db.database.getVersion();
    if (version > 0) {
      final list = await db.repositories.patient.queryable.where((x) {
        final List<IDbColumnCondition> arr = [];
        arr.add(x.isValid.equals(true));
        arr.add(x.userCode.equals(''));
        return arr;
      }).toList();
      logger.w(
          "PatientManager resettingUsercodeIsEmptyData list.count:${list.length}.");
      for (var element in list) {
        if (element.syncState == OfflineDataSyncState.success) {
          var result = await getDetail(element.code);
          if (result != null) {
            element.userCode = result.createdDoctor!;
          }
        } else {
          element.userCode = Store.user.userCode!;
        }
        await db.repositories.patient.update(element);
      }
    }
  }
}
