import 'dart:convert';

import 'package:fis_jsonrpc/services/completionRecord.m.dart';
import 'package:fis_jsonrpc/services/patient.m.dart';
import 'package:fis_jsonrpc/services/patientExtension.m.dart';
import 'package:vitalapp/database/db.dart';
import 'package:vitalapp/database/entities/defines.dart';
import 'package:vitalapp/database/entities/patient.dart';
import 'package:vitalapp/managers/interfaces/patient.dart';
import 'package:fis_common/logger/logger.dart';

class PatientOfflineStoreAdapter implements IPatientStoreAdapter {
  @override
  Future<String?> create(CreatePatientRequest request) async {
    // await db.database.execute("DROP TABLE IF EXISTS Patients;");
    // await db.database.execute(PatientEntity.TABLE_CREATE_SQL);
    final dto = PatientDtoConverter.create2Dto(request);
    final dtoJson = dto.toJson();

    final entity = PatientEntity();
    entity.code = request.code!;
    entity.isValid = true;
    entity.name = request.patientName!;
    entity.dataJson = jsonEncode(dtoJson);

    final id = await db.repositories.patient.insert(entity);
    print("Patient Id: $id");

    return id > 0 ? entity.code : null;
  }

  @override
  Future<bool> updatePatientAsync(UpdatePatientRequest request) async {
    PatientEntity? entity =
        await db.repositories.patient.singleByCode(request.code!);
    PatientDTO dto;
    if (entity == null) {
      entity = PatientEntity();
      entity.isValid = true;
      entity.syncType = OfflineDataSyncType.update;

      final id = await db.repositories.patient.insert(entity);
      if (id == 0) {
        logger.i("PatientOfflineStoreAdapter insert patient update fail.");
        return false;
      }

      dto = PatientDTO();
    } else {
      final jsonMap = jsonDecode(entity.dataJson);
      dto = PatientDTO.fromJson(jsonMap);
    }
    if (entity.syncType == OfflineDataSyncType.create) {
      if (entity.syncState == OfflineDataSyncState.success) {
        entity.syncType = OfflineDataSyncType.update;
        entity.syncState = OfflineDataSyncState.wait;
      }
    }

    PatientDtoConverter.syncUpdate2Dto(dto, request);

    entity.name = request.patientName!;
    entity.dataJson = jsonEncode(dto.toJson());

    final count = await db.repositories.patient.update(entity);
    // final dataJson = jsonEncode(dto.toJson());
    // final count = await db.repositories.patient.queryable
    //     .where((x) => [x.code.equals(dto.code)])
    //     .update((x) => [x.dataJson.update(dataJson)]);
    print("Patient Update count: $count");

    return count > 0;
  }

  @override
  Future<PatientDTO?> getDetail(String code) async {
    final entity = await db.repositories.patient.singleByCode(code);
    if (entity == null || entity.dataJson.isEmpty) {
      return null;
    }
    final jsonMap = jsonDecode(entity.dataJson);
    final dto = PatientDTO.fromJson(jsonMap);
    return dto;
  }

  @override
  Future<bool> setCrowdLabelsAsync(
      String patientCode, List<String> carowLabels) async {
    final dto = await getDetail(patientCode);
    if (dto == null) {
      return false;
    }

    dto.crowdLabels = carowLabels;
    final dataJson = jsonEncode(dto.toJson());

    final count = await db.repositories.patient.queryable
        .where((x) => [x.code.equals(patientCode)])
        .update((x) => [x.dataJson.update(dataJson)]);
    print("Patient setCrowdLabelsAsync count: $count");

    return count > 0;
  }

  @override
  Future<PatientExtensionDTO?> getPatientExtensionDetailByCodeAndKeyAsync(
      GetPatientExtensionByCodeAndKeyRequest request) {
    // TODO: implement getPatientExtensionDetailByCodeAndKeyAsync
    throw UnimplementedError();
  }

  @override
  Future<String> createPatientExtensionAsync(
      CreatePatientExtensionRequest request) {
    // TODO: implement createPatientExtensionAsync
    throw UnimplementedError();
  }

  @override
  Future<bool> updatePatientExtensionAsync(
      UpdatePatientExtensionRequest request) {
    // TODO: implement updatePatientExtensionAsync
    throw UnimplementedError();
  }

  @override
  Future<PageCollection<PatientDTO>?> getPagedList(PatientPageRequest request) {
    throw UnimplementedError();
  }
}

abstract class PatientDtoConverter {
  /// 根据新建请求创建DTO
  static PatientDTO create2Dto(CreatePatientRequest request) {
    final dto = PatientDTO();
    dto.code = request.code;
    dto.patientName = request.patientName;
    dto.phone = request.phone;
    dto.cardNo = request.cardNo;
    dto.nationality = request.nationality;
    dto.birthday = request.birthday;
    dto.crowdLabels = request.crowdLabels;
    dto.cardType = request.cardType;
    dto.patientGender = request.patientGender;
    dto.patientAddress = request.patientAddress;
    dto.permanentResidenceAddress = request.permanentResidenceAddress;
    dto.teamRegionCode = request.teamRegionCode;
    dto.contractedDoctor = request.contractedDoctor;
    return dto;
  }

  /// 根据DTO创建新建请求
  static CreatePatientRequest dto2Create(PatientDTO dto) {
    final dtoJson = dto.toJson();
    final request = CreatePatientRequest.fromJson(dtoJson);
    return request;
  }

  /// 同步更新到DTO
  static void syncUpdate2Dto(PatientDTO dto, UpdatePatientRequest request) {
    dto.code = request.code;
    dto.patientName = request.patientName;
    dto.phone = request.phone;
    dto.cardNo = request.cardNo;
    dto.nationality = request.nationality;
    dto.birthday = request.birthday;
    dto.crowdLabels = request.crowdLabels;
    if (request.cardType != null) {
      dto.cardType = request.cardType!;
    }
    if (request.patientGender != null) {
      dto.patientGender = request.patientGender!;
    }
    dto.patientAddress = request.patientAddress;
    dto.permanentResidenceAddress = request.permanentResidenceAddress;
    dto.teamRegionCode = request.teamRegionCode;
    dto.contractedDoctor = request.contractedDoctor;
  }

  /// 根据DTO创建更新请求
  static UpdatePatientRequest dto2Update(PatientDTO dto) {
    final dtoJson = dto.toJson();
    final request = UpdatePatientRequest.fromJson(dtoJson);
    return request;
  }
}

abstract class PatientExtDtoConverter {
  /// 根据新建请求创建DTO
  static PatientExtensionDTO create2Dto(CreatePatientExtensionRequest request) {
    final dto = PatientExtensionDTO();
    // dto.code = request.code;
    // dto.patientName = request.patientName;
    // dto.phone = request.phone;
    // dto.cardNo = request.cardNo;
    // dto.nationality = request.nationality;
    // dto.birthday = request.birthday;
    // dto.crowdLabels = request.crowdLabels;
    // dto.cardType = request.cardType;
    // dto.patientGender = request.patientGender;
    // dto.patientAddress = request.patientAddress;
    // dto.permanentResidenceAddress = request.permanentResidenceAddress;
    // dto.teamRegionCode = request.teamRegionCode;
    // dto.contractedDoctor = request.contractedDoctor;
    return dto;
  }

  /// 根据DTO创建新建请求
  static CreatePatientExtensionRequest dto2Create(PatientExtensionDTO dto) {
    final dtoJson = dto.toJson();
    final request = CreatePatientExtensionRequest.fromJson(dtoJson);
    return request;
  }

  /// 同步更新到DTO
  static void syncUpdate2Dto(
      PatientExtensionDTO dto, UpdatePatientExtensionRequest request) {}

  /// 根据DTO创建更新请求
  static UpdatePatientExtensionRequest dto2Update(PatientExtensionDTO dto) {
    final dtoJson = dto.toJson();
    final request = UpdatePatientExtensionRequest.fromJson(dtoJson);
    return request;
  }
}
