package com.lantone.daqe.facade;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.lantone.common.enums.IsDeleteEnum;
import com.lantone.common.util.BeanUtil;
import com.lantone.common.util.DateUtil;
import com.lantone.common.util.EntityUtil;
import com.lantone.common.util.ListUtil;
import com.lantone.common.util.StringUtil;
import com.lantone.common.util.SysUserUtils;
import com.lantone.common.vo.BlockLossTypeGatherVO;
import com.lantone.common.vo.DataRepariVO;
import com.lantone.daqe.client.OperationLogService;
import com.lantone.daqe.dto.BlockLossTypeGatherDTO;
import com.lantone.daqe.dto.GetBlockLossPageDTO;
import com.lantone.common.dto.GetOperationLogDTO;
import com.lantone.daqe.dto.HisMedicalRecordDTO;
import com.lantone.daqe.dto.UpBlockLossByIdVO;
import com.lantone.daqe.entity.BehospitalInfo;
import com.lantone.daqe.entity.BlocklossResult;
import com.lantone.daqe.entity.HomePage;
import com.lantone.daqe.entity.MedicalRecord;
import com.lantone.daqe.entity.MedicalRecordContent;
import com.lantone.daqe.enums.LossStatusEnum;
import com.lantone.daqe.enums.LossTypeEnum;
import com.lantone.daqe.enums.LossWayEnum;
import com.lantone.daqe.facade.base.BehospitalInfoFacade;
import com.lantone.daqe.facade.base.BlocklossResultFacade;
import com.lantone.common.vo.DataCompareVO;
import com.lantone.daqe.facade.base.HomePageFacade;
import com.lantone.daqe.facade.base.MedicalRecordContentFacade;
import com.lantone.daqe.facade.base.MedicalRecordFacade;
import com.lantone.daqe.service.impl.BlocklossResultServiceImpl;
import com.lantone.daqe.vo.GetBlockLossPageVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Description: 病历数据丢失明细-业务处理类
 * @author: songxl
 * @time: 2022/3/4 10:39
 */
@Component
public class BlockLossManagementFacade {
    @Autowired
    private BlocklossResultFacade blocklossResultFacade;
    @Autowired
    private BlocklossResultServiceImpl blocklossResultServiceImpl;
    @Autowired
    private BehospitalInfoFacade behospitalInfoFacade;
    @Autowired
    private HomePageFacade homePageFacade;
    @Autowired
    private MedicalRecordFacade medicalRecordFacade;
    @Autowired
    private MedicalRecordContentFacade medicalRecordContentFacade;
    @Autowired
    private OperationLogService operationLogService;

    @Autowired
    private HisDataManagementFacade hisDataManagementFacade;


    /**
     * 获取病历数据丢失明细分页列表
     *
     * @param getBlockLossPageVO
     * @Return com.baomidou.mybatisplus.core.metadata.IPage<com.lantone.daqe.dto.GetBlockLossPageDTO>
     */
    public IPage<GetBlockLossPageDTO> getBlockLossPage(GetBlockLossPageVO getBlockLossPageVO) {
        return blocklossResultFacade.getBaseMapper().getBlockLossPage(getBlockLossPageVO);
    }

    /**
     * 通过id修改病历数据块丢失明细
     *
     * @param upBlockLossByIdVO
     * @Return java.lang.Boolean
     */
    public Boolean upBlockLossById(UpBlockLossByIdVO upBlockLossByIdVO) {
        BlocklossResult blocklossResult = new BlocklossResult();
        BeanUtils.copyProperties(upBlockLossByIdVO, blocklossResult);
        blocklossResult.setModifier(SysUserUtils.getCurrentPrinciple() == null ? "0" : SysUserUtils.getCurrentPrinciple());
        blocklossResult.setGmtModified(DateUtil.now());
        blocklossResult.setAuditTime(DateUtil.now());
        return blocklossResultFacade.updateById(blocklossResult);
    }

    /**
     * 数据对比
     *
     * @param dataCompareVO
     * @Return java.lang.Boolean
     */
    public Boolean dataCompare(DataCompareVO dataCompareVO) {
        Boolean flag = false;
        Long hospitalId = null;
        Long principleId = null;
        //定时任务SysUserUtils取不到医院，操作人
        if (dataCompareVO.getHospitalId() == null) {
            hospitalId = SysUserUtils.getCurrentHospitalId();
            principleId = SysUserUtils.getCurrentPrincipleId();
        }


        //====1.获取已丢失状态记录，去数据库中对比判断是否补录
        List<BlocklossResult> lossResults = blocklossResultFacade.list(new QueryWrapper<BlocklossResult>()
                .select("id,behospital_code,rec_id,loss_type,loss_way")
                .eq(hospitalId != null, "hospital_id", hospitalId)
                .eq("status", LossStatusEnum.IS_LOSS.getKey())
                .eq("is_deleted", IsDeleteEnum.N.getKey()));
        Map<String, List<BlocklossResult>> lossResultMap = null;
        if (ListUtil.isNotEmpty(lossResults)) {
            lossResultMap = EntityUtil.makeEntityListMap(lossResults, "lossType");
            //更新以缺失数据的状态
            flag = upBlockLossStatus(lossResultMap, hospitalId, principleId);
        }

        //====2.某时间的数据对比
        //=====2.1获取数据

        //获取his对应的数据
        List<HisMedicalRecordDTO> hisMedicalRecords = getHisMedicalRecords(dataCompareVO);
        Map<String, HisMedicalRecordDTO> hisMedicalRecordMap = EntityUtil.makeEntityMap(hisMedicalRecords, "behospitalCode");

        //获取操作记录数据
        //病历数据
        dataCompareVO.setOperationUrl("save/saveBehospitalCode");
        List<GetOperationLogDTO> behospitalCodeLogs = getOperationLogs(dataCompareVO);
        //病案首页数据
        List<GetOperationLogDTO> homePageLogs = new ArrayList<>();
        //文书数据
        List<GetOperationLogDTO> recLogs = new ArrayList<>();

        List<String> logCodes = null;
        //没有病历数据就不用去查病案首页和文书
        if (ListUtil.isNotEmpty(behospitalCodeLogs)) {
            //日志去重防止多次操作
            behospitalCodeLogs = removeRepeat(behospitalCodeLogs, "behospitalCode");
            logCodes = behospitalCodeLogs.stream().map(GetOperationLogDTO::getBehospitalCode).collect(Collectors.toList());
            dataCompareVO.setBehospitalCodes(logCodes);
            //病案首页数据
            dataCompareVO.setOperationUrl("save/saveHomePages");
            homePageLogs = removeRepeat(getOperationLogs(dataCompareVO), "homePageId");
            //文书数据
            dataCompareVO.setOperationUrl("save/saveRecs");
            recLogs = removeRepeat(getOperationLogs(dataCompareVO), "recTitle");
        }

        //获取库中数据
        //病历数据
        List<String> dataBaseBehospitalCodes = behospitalInfoFacade.list(new QueryWrapper<BehospitalInfo>()
                .select("behospital_code")
                .ge(dataCompareVO.getStartDate() != null && StringUtil.isBlank(dataCompareVO.getBehospitalCode()), "gmt_create", dataCompareVO.getStartDate())
                .le(dataCompareVO.getEndDate() != null && StringUtil.isBlank(dataCompareVO.getBehospitalCode()), "gmt_create", dataCompareVO.getEndDate())
                .eq(StringUtil.isNotBlank(dataCompareVO.getBehospitalCode()), "behospital_code", dataCompareVO.getBehospitalCode())
                .eq(hospitalId != null, "hospital_id", hospitalId)
                .eq("is_deleted", IsDeleteEnum.N.getKey()))
                .stream().map(BehospitalInfo::getBehospitalCode).collect(Collectors.toList());
        //病案首页数据
        List<String> dataBaseHomePageIds = new ArrayList<>();
        //文书数据
        List<String> dataBaseRecIds = new ArrayList<>();
        if (ListUtil.isNotEmpty(dataBaseBehospitalCodes)) {
            dataBaseHomePageIds = homePageFacade.list(new QueryWrapper<HomePage>()
                    .select("home_page_id")
                    .in("behospital_code", dataBaseBehospitalCodes)
                    .eq(hospitalId != null, "hospital_id", hospitalId)
                    .eq("is_deleted", IsDeleteEnum.N.getKey()))
                    .stream().map(HomePage::getHomePageId).collect(Collectors.toList());
            dataBaseRecIds = medicalRecordFacade.list(new QueryWrapper<MedicalRecord>()
                    .select("rec_id")
                    .in("behospital_code", dataBaseBehospitalCodes)
                    .eq(hospitalId != null, "hospital_id", hospitalId)
                    .eq("is_deleted", IsDeleteEnum.N.getKey()))
                    .stream().map(MedicalRecord::getRecId).collect(Collectors.toList());
        }

        //==已丢失 外部|内部 病历、文书、病案首页 id集合
        //外部
        List<String> outLossCodes = null;
        List<String> outLossHomepages = null;
        List<String> outLossRecs = null;
        //内部
        List<String> inLossCodes = null;
        List<String> inLossHomepages = null;
        List<String> inLossRecs = null;
        if (lossResultMap != null) {
            if (ListUtil.isNotEmpty(lossResultMap.get(LossTypeEnum.REC_LOSS.getKey()))) {
                Map<String, List<BlocklossResult>> lossWayRecMap = EntityUtil.makeEntityListMap(lossResultMap.get(LossTypeEnum.REC_LOSS.getKey()), "lossWay");
                if (ListUtil.isNotEmpty(lossWayRecMap.get(LossWayEnum.OUT_LOSS.getKey()))) {
                    outLossRecs = lossWayRecMap.get(LossWayEnum.OUT_LOSS.getKey()).stream().map(BlocklossResult::getRecId).collect(Collectors.toList());
                }
                if (ListUtil.isNotEmpty(lossWayRecMap.get(LossWayEnum.IN_LOSS.getKey()))) {
                    inLossRecs = lossWayRecMap.get(LossWayEnum.IN_LOSS.getKey()).stream().map(BlocklossResult::getRecId).collect(Collectors.toList());
                }
            }
            if (ListUtil.isNotEmpty(lossResultMap.get(LossTypeEnum.HOMEPAGE_LOSS.getKey()))) {
                Map<String, List<BlocklossResult>> lossWayHomePageMap = EntityUtil.makeEntityListMap(lossResultMap.get(LossTypeEnum.HOMEPAGE_LOSS.getKey()), "lossWay");
                if (ListUtil.isNotEmpty(lossWayHomePageMap.get(LossWayEnum.OUT_LOSS.getKey()))) {
                    outLossHomepages = lossWayHomePageMap.get(LossWayEnum.OUT_LOSS.getKey()).stream().map(BlocklossResult::getRecId).collect(Collectors.toList());
                }
                if (ListUtil.isNotEmpty(lossWayHomePageMap.get(LossWayEnum.IN_LOSS.getKey()))) {
                    inLossHomepages = lossWayHomePageMap.get(LossWayEnum.IN_LOSS.getKey()).stream().map(BlocklossResult::getRecId).collect(Collectors.toList());
                }
            }
            if (ListUtil.isNotEmpty(lossResultMap.get(LossTypeEnum.CODE_LOSS.getKey()))) {
                Map<String, List<BlocklossResult>> lossWayCodeMap = EntityUtil.makeEntityListMap(lossResultMap.get(LossTypeEnum.CODE_LOSS.getKey()), "lossWay");
                if (ListUtil.isNotEmpty(lossWayCodeMap.get(LossWayEnum.OUT_LOSS.getKey()))) {
                    outLossCodes = lossWayCodeMap.get(LossWayEnum.OUT_LOSS.getKey()).stream().map(BlocklossResult::getBehospitalCode).collect(Collectors.toList());
                }
                if (ListUtil.isNotEmpty(lossWayCodeMap.get(LossWayEnum.IN_LOSS.getKey()))) {
                    inLossCodes = lossWayCodeMap.get(LossWayEnum.IN_LOSS.getKey()).stream().map(BlocklossResult::getBehospitalCode).collect(Collectors.toList());
                }
            }
        }

        //=====2.2数据对比
        //his与log日志做对比
        if (ListUtil.isNotEmpty(hisMedicalRecords)) {
            //获取His病历数据 - His病案首页数据
            List<GetOperationLogDTO> medicalRecords = BeanUtil.listCopyTo(hisMedicalRecords, GetOperationLogDTO.class);
            //获取His文书数据
            List<GetOperationLogDTO> recs = new ArrayList<>();
            hisMedicalRecords.stream().forEach(hisMedicalRecordDTO -> {
                if (ListUtil.isNotEmpty(hisMedicalRecordDTO.getHisRecs())) {
                    hisMedicalRecordDTO.getHisRecs().stream().forEach(hisRecDTO -> {
                        GetOperationLogDTO medicalRecord = new GetOperationLogDTO();
                        medicalRecord.setRecId(hisRecDTO.getRecId());
                        medicalRecord.setRecTitle(hisRecDTO.getRecTitle());
                        medicalRecord.setBehospitalCode(hisMedicalRecordDTO.getBehospitalCode());
                        recs.add(medicalRecord);
                    });

                }
            });
            //外部丢失数据集合
            List<BlocklossResult> outInserts = new ArrayList<>();
            //文书数据对比
            compareHisWithLog(recs, recLogs, LossTypeEnum.REC_LOSS.getKey(), outInserts, outLossRecs, hisMedicalRecordMap, hospitalId, principleId);
            //病案首页数据对比
            compareHisWithLog(medicalRecords, homePageLogs, LossTypeEnum.HOMEPAGE_LOSS.getKey(), outInserts, outLossHomepages, hisMedicalRecordMap, hospitalId, principleId);
            //病历数据对比
            compareHisWithLog(medicalRecords, behospitalCodeLogs, LossTypeEnum.CODE_LOSS.getKey(), outInserts, outLossCodes, hisMedicalRecordMap, hospitalId, principleId);

            flag = blocklossResultServiceImpl.saveBatch(outInserts);
        }

        //日志与入库数据对比
        //内部丢失数据集合
        List<BlocklossResult> inInserts = new ArrayList<>();
        if (ListUtil.isNotEmpty(recLogs)) {
            compareLogWithLocal(recLogs, dataBaseRecIds, LossTypeEnum.REC_LOSS.getKey(), inInserts, inLossRecs, hisMedicalRecordMap, hospitalId, principleId);
        }
        if (ListUtil.isNotEmpty(homePageLogs)) {
            compareLogWithLocal(homePageLogs, dataBaseHomePageIds, LossTypeEnum.HOMEPAGE_LOSS.getKey(), inInserts, inLossHomepages, hisMedicalRecordMap, hospitalId, principleId);
        }
        if (ListUtil.isNotEmpty(behospitalCodeLogs)) {
            compareLogWithLocal(behospitalCodeLogs, dataBaseBehospitalCodes, LossTypeEnum.CODE_LOSS.getKey(), inInserts, inLossCodes, hisMedicalRecordMap, hospitalId, principleId);
        }
        if (ListUtil.isNotEmpty(inInserts)) {
            flag = blocklossResultServiceImpl.saveBatch(inInserts);
        }
        return flag;
    }

    /**
     * 数据去重
     *
     * @param homePageLogs
     * @param key
     * @Return java.util.List<com.lantone.common.dto.GetOperationLogDTO>
     */
    private List<GetOperationLogDTO> removeRepeat(List<GetOperationLogDTO> homePageLogs, String key) {
        Map<String, GetOperationLogDTO> tempMap = EntityUtil.makeEntityMap(homePageLogs, key);
        List<GetOperationLogDTO> out = new ArrayList<>();
        tempMap.keySet().stream().forEach(id -> {
            out.add(tempMap.get(id));
        });
        return out;
    }

    /**
     * 日志与入库数据对比
     *
     * @param logs                日志记录
     * @param dataBases           入库数据
     * @param type                对比类型：0:文书丢失 1:病案首页丢失 2:患者信息丢失
     * @param inInserts           内部丢失插入集合
     * @param havingLossIds       已经插入的id集合
     * @param hisMedicalRecordMap his病历数据map（key-住院序号：value-人的his数据）
     * @param hospitalId          医院id
     * @param principleId         操作人id
     * @Return void
     */
    private void compareLogWithLocal(List<GetOperationLogDTO> logs, List<String> dataBases, String type,
                                     List<BlocklossResult> inInserts, List<String> havingLossIds,
                                     Map<String, HisMedicalRecordDTO> hisMedicalRecordMap, Long hospitalId, Long principleId) {
        switch (type) {
            case "0":
                //文书丢失
                logs.stream().forEach(rec -> {
                    //存在记录但是没有入库
                    if (!dataBases.contains(rec.getRecId())) {
                        if (havingLossIds == null || !havingLossIds.contains(rec.getRecId())) {
                            BlocklossResult blocklossResult = new BlocklossResult();
                            blocklossResult.setBehospitalCode(rec.getBehospitalCode());
                            blocklossResult.setRecId(rec.getRecId());
                            blocklossResult.setRecTitle(rec.getRecTitle());
                            blocklossResult.setLossWay(LossWayEnum.IN_LOSS.getKey());
                            blocklossResult.setLossType(LossTypeEnum.REC_LOSS.getKey());
                            if (hisMedicalRecordMap.get(rec.getBehospitalCode()) != null) {
                                blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(rec.getBehospitalCode()).getBehospitalDate());
                            }
                            //拼装病历数据块丢失明细其他信息
                            assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                            inInserts.add(blocklossResult);
                        }
                    }
                });
                //判断只插入文书id的情况
                //获取插入的文书
                if (ListUtil.isNotEmpty(dataBases)) {
                    List<String> havingRecIds = medicalRecordContentFacade.list(new QueryWrapper<MedicalRecordContent>()
                            .select("rec_id")
                            .in("rec_id", dataBases)).stream().map(MedicalRecordContent::getRecId).collect(Collectors.toList());
                    List<String> tempList = new ArrayList<>(dataBases);
                    //移除查出来有内容的文书
                    tempList.removeAll(havingRecIds);
                    Map<String, GetOperationLogDTO> recMap = EntityUtil.makeEntityMap(logs, "recId");
                    //有文书id无内容文书
                    tempList.stream().forEach(recId -> {
                        //没有被记录过
                        if (havingLossIds == null || !havingLossIds.contains(recId)) {
                            BlocklossResult blocklossResult = new BlocklossResult();
                            blocklossResult.setBehospitalCode(recMap.get(recId).getBehospitalCode());
                            blocklossResult.setRecId(recId);
                            blocklossResult.setRecTitle(recMap.get(recId).getRecTitle());
                            blocklossResult.setLossWay(LossWayEnum.IN_LOSS.getKey());
                            blocklossResult.setLossType(LossTypeEnum.REC_LOSS.getKey());
                            blocklossResult.setLossCause("文书id插入成功，文书内容没有插入");
                            if (hisMedicalRecordMap.get(recMap.get(recId)) != null) {
                                blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(recMap.get(recId).getBehospitalCode()).getBehospitalDate());
                            }
                            //拼装病历数据块丢失明细其他信息
                            assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                            inInserts.add(blocklossResult);
                        }
                    });
                }

                break;
            case "1":
                //病案首页丢失
                logs.stream().forEach(homePages -> {
                    //存在记录但是没有入库
                    if (!dataBases.contains(homePages.getRecId())) {
                        if (havingLossIds == null || !havingLossIds.contains(homePages.getHomePageId())) {
                            BlocklossResult blocklossResult = new BlocklossResult();
                            blocklossResult.setBehospitalCode(homePages.getBehospitalCode());
                            blocklossResult.setRecId(homePages.getHomePageId());
                            blocklossResult.setRecTitle("病案首页丢失");
                            blocklossResult.setLossWay(LossWayEnum.IN_LOSS.getKey());
                            blocklossResult.setLossType(LossTypeEnum.HOMEPAGE_LOSS.getKey());
                            if (hisMedicalRecordMap.get(homePages.getBehospitalCode()) != null) {
                                blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(homePages.getBehospitalCode()).getBehospitalDate());
                            }
                            //拼装病历数据块丢失明细其他信息
                            assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                            inInserts.add(blocklossResult);
                        }
                    }
                });
                break;
            case "2":
                //患者信息丢失
                logs.stream().forEach(beHehospitalInfo -> {
                    //存在记录但是没有入库
                    if (!dataBases.contains(beHehospitalInfo.getBehospitalCode())) {
                        if (havingLossIds == null || !havingLossIds.contains(beHehospitalInfo.getBehospitalCode())) {
                            BlocklossResult blocklossResult = new BlocklossResult();
                            blocklossResult.setBehospitalCode(beHehospitalInfo.getBehospitalCode());
                            blocklossResult.setLossWay(LossWayEnum.IN_LOSS.getKey());
                            blocklossResult.setLossType(LossTypeEnum.CODE_LOSS.getKey());
                            if (hisMedicalRecordMap.get(beHehospitalInfo.getBehospitalCode()) != null) {
                                blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(beHehospitalInfo.getBehospitalCode()).getBehospitalDate());
                            }
                            //拼装病历数据块丢失明细其他信息
                            assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                            inInserts.add(blocklossResult);
                        }
                    }
                });
                break;
            default:
                break;
        }

    }

    /**
     * 更新以缺失数据的状态
     *
     * @param lossResultMap
     * @Return void
     */
    private Boolean upBlockLossStatus(Map<String, List<BlocklossResult>> lossResultMap, Long hospitalId, Long principleId) {
        AtomicReference<Boolean> flag = new AtomicReference<>(false);
        lossResultMap.keySet().stream().forEach(lossType -> {
            //0:文书丢失 1:病案首页丢失 2:患者信息丢失
            switch (lossType) {
                case "0":
                    //文书丢失
                    List<String> redIds = medicalRecordFacade.list(new QueryWrapper<MedicalRecord>()
                            .eq("hospital_id", hospitalId != null ? hospitalId : 0)
                            .in("rec_id", lossResultMap.get(lossType).stream().map(BlocklossResult::getRecId).collect(Collectors.toList()))
                            .in("behospital_code", lossResultMap.get(lossType).stream().map(BlocklossResult::getBehospitalCode).collect(Collectors.toList()))
                            .eq("is_deleted", IsDeleteEnum.N.getKey()))
                            .stream().map(MedicalRecord::getRecId).collect(Collectors.toList());
                    //更新状态-已恢复
                    if (ListUtil.isNotEmpty(redIds)) {
                        flag.set(blocklossResultFacade.update(new UpdateWrapper<BlocklossResult>()
                                .set("solve_time", DateUtil.now())
                                .set("gmt_modified", DateUtil.now())
                                .set("status", LossStatusEnum.NOT_LOSS.getKey())
                                .set("modifier", principleId != null ? principleId + "" : "0")
                                .eq("status", LossStatusEnum.IS_LOSS.getKey())
                                .eq("loss_type", lossType)
                                .eq("is_deleted", IsDeleteEnum.N.getKey())
                                .eq("hospital_id", hospitalId != null ? hospitalId : 0)
                                .in("rec_id", redIds)));
                    }
                    break;
                case "1":
                    //病案首页丢失
                    List<String> homePages = homePageFacade.list(new QueryWrapper<HomePage>()
                            .eq("hospital_id", hospitalId != null ? hospitalId : 0)
                            .in("home_page_id", lossResultMap.get(lossType).stream().map(BlocklossResult::getRecId).collect(Collectors.toList()))
                            .in("behospital_code", lossResultMap.get(lossType).stream().map(BlocklossResult::getBehospitalCode).collect(Collectors.toList()))
                            .eq("is_deleted", IsDeleteEnum.N.getKey()))
                            .stream().map(HomePage::getHomePageId).collect(Collectors.toList());

                    //更新状态-已恢复
                    if (ListUtil.isNotEmpty(homePages)) {
                        flag.set(blocklossResultFacade.update(new UpdateWrapper<BlocklossResult>()
                                .set("solve_time", DateUtil.now())
                                .set("gmt_modified", DateUtil.now())
                                .set("status", LossStatusEnum.NOT_LOSS.getKey())
                                .set("modifier", principleId != null ? principleId + "" : "0")
                                .eq("status", LossStatusEnum.IS_LOSS.getKey())
                                .eq("loss_type", lossType)
                                .eq("hospital_id", hospitalId != null ? hospitalId : 0)
                                .in("rec_id", homePages)
                                .eq("is_deleted", IsDeleteEnum.N.getKey())));
                    }
                    break;
                case "2":
                    //患者信息丢失
                    List<String> behospitalCodes = behospitalInfoFacade.list(new QueryWrapper<BehospitalInfo>()
                            .eq("hospital_id", hospitalId != null ? hospitalId : 0)
                            .in("behospital_code", lossResultMap.get(lossType).stream().map(BlocklossResult::getBehospitalCode).collect(Collectors.toList()))
                            .eq("is_deleted", IsDeleteEnum.N.getKey()))
                            .stream().map(BehospitalInfo::getBehospitalCode).collect(Collectors.toList());
                    //更新状态-已恢复
                    if (ListUtil.isNotEmpty(behospitalCodes)) {
                        flag.set(blocklossResultFacade.update(new UpdateWrapper<BlocklossResult>()
                                .set("solve_time", DateUtil.now())
                                .set("gmt_modified", DateUtil.now())
                                .set("status", LossStatusEnum.NOT_LOSS.getKey())
                                .set("modifier", principleId != null ? principleId + "" : "0")
                                .eq("status", LossStatusEnum.IS_LOSS.getKey())
                                .eq("loss_type", lossType)
                                .eq("is_deleted", IsDeleteEnum.N.getKey())
                                .eq("hospital_id", hospitalId != null ? hospitalId : 0)
                                .in("behospital_code", behospitalCodes)));
                    }
                    break;
                default:
                    break;
            }
        });
        return flag.get();
    }

    /**
     * @param medicalRecords      his数据
     * @param logs                日志数据
     * @param type                对比类型：0:文书丢失 1:病案首页丢失 2:患者信息丢失
     * @param outInserts          外部丢失插入集合
     * @param havingLossIds       已经插入的id集合
     * @param hisMedicalRecordMap his病历数据map（key-住院序号：value-人的his数据）
     * @param hospitalId          医院id
     * @param principleId         操作人id
     * @Return void
     */
    private void compareHisWithLog(List<GetOperationLogDTO> medicalRecords, List<GetOperationLogDTO> logs,
                                   String type, List<BlocklossResult> outInserts, List<String> havingLossIds,
                                   Map<String, HisMedicalRecordDTO> hisMedicalRecordMap, Long hospitalId, Long principleId) {
        //his数据为空直接返回
        if (ListUtil.isEmpty(medicalRecords)) {
            return;
        }
        switch (type) {
            case "0":
                List<String> recLogs = logs.stream().map(GetOperationLogDTO::getRecId).collect(Collectors.toList());
                medicalRecords.stream().forEach(medicalRecord -> {
                    //文书不存在操作记录
                    if (StringUtil.isNotEmpty(medicalRecord.getRecId())) {
                        if (!recLogs.contains(medicalRecord.getRecId())) {
                            //该记录没有插入
                            if (havingLossIds == null || ListUtil.isNotEmpty(havingLossIds) && !havingLossIds.contains(medicalRecord.getRecId())) {
                                BlocklossResult blocklossResult = new BlocklossResult();
                                blocklossResult.setBehospitalCode(medicalRecord.getBehospitalCode());
                                blocklossResult.setRecId(medicalRecord.getRecId());
                                blocklossResult.setRecTitle(medicalRecord.getRecTitle());
                                blocklossResult.setLossWay(LossWayEnum.OUT_LOSS.getKey());
                                blocklossResult.setLossType(LossTypeEnum.REC_LOSS.getKey());
                                blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(medicalRecord.getBehospitalCode()).getBehospitalDate());
                                //拼装病历数据块丢失明细其他信息
                                assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                                outInserts.add(blocklossResult);
                            }
                        }
                    }
                });
                break;
            case "1":
                List<String> homepageLogs = logs.stream().map(GetOperationLogDTO::getHomePageId).collect(Collectors.toList());
                medicalRecords.stream().forEach(medicalRecord -> {
                    //病案首页不存在操作记录
                    if (StringUtil.isNotEmpty(medicalRecord.getHomePageId()) && !homepageLogs.contains(medicalRecord.getHomePageId())) {
                        if (havingLossIds == null || ListUtil.isNotEmpty(havingLossIds) && !havingLossIds.contains(medicalRecord.getHomePageId())) {
                            BlocklossResult blocklossResult = new BlocklossResult();
                            blocklossResult.setBehospitalCode(medicalRecord.getBehospitalCode());
                            blocklossResult.setRecId(medicalRecord.getHomePageId());
                            blocklossResult.setRecTitle("病案首页丢失");
                            blocklossResult.setLossWay(LossWayEnum.OUT_LOSS.getKey());
                            blocklossResult.setLossType(LossTypeEnum.HOMEPAGE_LOSS.getKey());
                            blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(medicalRecord.getBehospitalCode()).getBehospitalDate());
                            //拼装病历数据块丢失明细其他信息
                            assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                            outInserts.add(blocklossResult);
                        }
                    }
                });
                break;
            case "2":
                List<String> behospitalCodeLogs = logs.stream().map(GetOperationLogDTO::getBehospitalCode).collect(Collectors.toList());
                medicalRecords.stream().forEach(medicalRecord -> {
                    //病历数据不存在操作记录
                    if (!behospitalCodeLogs.contains(medicalRecord.getBehospitalCode())) {
                        if (havingLossIds == null || ListUtil.isNotEmpty(havingLossIds) && !havingLossIds.contains(medicalRecord.getBehospitalCode())) {
                            BlocklossResult blocklossResult = new BlocklossResult();
                            blocklossResult.setBehospitalCode(medicalRecord.getBehospitalCode());
                            blocklossResult.setLossWay(LossWayEnum.OUT_LOSS.getKey());
                            blocklossResult.setLossType(LossTypeEnum.CODE_LOSS.getKey());
                            blocklossResult.setBehospitalDate(hisMedicalRecordMap.get(medicalRecord.getBehospitalCode()).getBehospitalDate());
                            //拼装病历数据块丢失明细其他信息
                            assembleOtherBlocklossResult(blocklossResult, hospitalId, principleId);
                            outInserts.add(blocklossResult);
                        }
                    }
                });
                break;
            default:
                break;
        }
    }

    /**
     * 拼装病历数据块丢失明细其他信息
     *
     * @param blocklossResult
     * @param hospitalId
     * @param principleId
     * @Return void
     */
    private void assembleOtherBlocklossResult(BlocklossResult blocklossResult, Long hospitalId, Long principleId) {
        blocklossResult.setStatus(LossStatusEnum.IS_LOSS.getKey());
        blocklossResult.setHospitalId(hospitalId != null ? hospitalId : 0);
        blocklossResult.setGmtCreate(DateUtil.now());
        blocklossResult.setCreator(principleId != null ? principleId + "" : "0");
        blocklossResult.setGmtModified(DateUtil.now());
    }


    /**
     * 获取操作记录数据
     *
     * @param dataCompareVO
     * @Return java.util.List<com.lantone.common.dto.GetOperationLogDTO>
     */
    private List<GetOperationLogDTO> getOperationLogs(DataCompareVO dataCompareVO) {
        return operationLogService.getOperationLogs(dataCompareVO).getData();
    }

    /**
     * 获取his对应的数据
     *
     * @param dataCompareVO
     * @Return java.util.List<com.lantone.daqe.dto.HisMedicalRecordDTO>
     */
    private List<HisMedicalRecordDTO> getHisMedicalRecords(DataCompareVO dataCompareVO) {
        //技术服务部接口 /balance/data/getDataCount
        //###模拟
        return hisDataManagementFacade.getHisMedicalRecords(dataCompareVO);
    }

    /**
     * 丢失量分类汇总
     *
     * @param blockLossTypeGatherVO
     * @Return com.lantone.daqe.dto.BlockLossTypeGatherDTO
     */
    public BlockLossTypeGatherDTO blockLossTypeGather(BlockLossTypeGatherVO blockLossTypeGatherVO) {
        blockLossTypeGatherVO.setOperationUrls(Lists.newArrayList("save/saveBehospitalCode",
                "save/saveHomePages",
                "save/saveRecs"));

        DataCompareVO dataCompareVO = new DataCompareVO();
        dataCompareVO.setStartDate(blockLossTypeGatherVO.getStartDate());
        dataCompareVO.setEndDate(blockLossTypeGatherVO.getEndDate());
        //获取his数据
        List<HisMedicalRecordDTO> hisMedicalRecords = getHisMedicalRecords(dataCompareVO);

        BlockLossTypeGatherDTO blockLossTypeGatherDTO = new BlockLossTypeGatherDTO();
        //his数据量
        blockLossTypeGatherDTO.setHisNum(getHisMedicalRecordsCount(hisMedicalRecords));

        //获取该时间段的日志数量
        //病历数据
        dataCompareVO.setOperationUrl("save/saveBehospitalCode");
        List<GetOperationLogDTO> behospitalCodeLogs = getOperationLogs(dataCompareVO);
        //病案首页数据
        List<GetOperationLogDTO> homePageLogs = new ArrayList<>();
        //文书数据
        List<GetOperationLogDTO> recLogs = new ArrayList<>();

        if (ListUtil.isNotEmpty(behospitalCodeLogs)) {
            List<String> logCodes = behospitalCodeLogs.stream().map(GetOperationLogDTO::getBehospitalCode).collect(Collectors.toList());
            dataCompareVO.setBehospitalCodes(logCodes);
            //病案首页数据
            dataCompareVO.setOperationUrl("save/saveHomePages");
            homePageLogs = getOperationLogs(dataCompareVO);
            //文书数据
            dataCompareVO.setOperationUrl("save/saveRecs");
            recLogs = getOperationLogs(dataCompareVO);
            Integer logNum = logCodes.size() + homePageLogs.size() + recLogs.size();
            blockLossTypeGatherDTO.setLogNum(logNum);
        }

        //获取该时间段的实际数量
        List<String> codes = behospitalInfoFacade.list(new QueryWrapper<BehospitalInfo>()
                .eq("hospital_id", SysUserUtils.getCurrentHospitalId() != null ? SysUserUtils.getCurrentHospitalId() : 0)
                .ge(blockLossTypeGatherVO.getStartDate() != null, "behospital_date", blockLossTypeGatherVO.getStartDate())
                .le(blockLossTypeGatherVO.getEndDate() != null, "behospital_date", blockLossTypeGatherVO.getEndDate()))
                .stream().map(BehospitalInfo::getBehospitalCode).collect(Collectors.toList());

        Integer codeNum = codes.size();
        Integer homePageNum = 0;
        Integer recNum = 0;
        if (ListUtil.isNotEmpty(codes)) {
            homePageNum = homePageFacade.count(new QueryWrapper<HomePage>()
                    .eq("hospital_id", SysUserUtils.getCurrentHospitalId() != null ? SysUserUtils.getCurrentHospitalId() : 0)
                    .in("behospital_code", codes));
            recNum = medicalRecordFacade.count(new QueryWrapper<MedicalRecord>()
                    .eq("hospital_id", SysUserUtils.getCurrentHospitalId() != null ? SysUserUtils.getCurrentHospitalId() : 0)
                    .in("behospital_code", codes));
        }

        blockLossTypeGatherDTO.setRealNum(codeNum + homePageNum + recNum);
        //获取该时间段的丢失数量
        List<BlocklossResult> blocklossResults = blocklossResultFacade.list(new QueryWrapper<BlocklossResult>()
                .eq("hospital_id", SysUserUtils.getCurrentHospitalId() != null ? SysUserUtils.getCurrentHospitalId() : 0)
                .eq("status", LossStatusEnum.IS_LOSS.getKey())
                .ge(blockLossTypeGatherVO.getStartDate() != null, "behospital_date", blockLossTypeGatherVO.getStartDate())
                .le(blockLossTypeGatherVO.getEndDate() != null, "behospital_date", blockLossTypeGatherVO.getEndDate()));
        Integer allLossNum = blocklossResults.size();
        blockLossTypeGatherDTO.setAllLossNum(allLossNum);
        //        blockLossTypeGatherDTO.setHisNum(codeNum + homePageNum + recNum + allLossNum);

        Map<String, List<BlocklossResult>> lossWayMap = EntityUtil.makeEntityListMap(blocklossResults, "lossWay");
        //外部丢失
        if (lossWayMap.get(LossWayEnum.OUT_LOSS.getKey()) != null) {
            Integer outLossNum = lossWayMap.get(LossWayEnum.OUT_LOSS.getKey()).size();
            blockLossTypeGatherDTO.setOutLossNum(outLossNum);
            if (lossWayMap.get(LossWayEnum.OUT_LOSS.getKey()) != null) {
                Map<String, List<BlocklossResult>> outLossTypeMap = EntityUtil.makeEntityListMap(lossWayMap.get(LossWayEnum.OUT_LOSS.getKey()), "lossType");
                if (outLossTypeMap.get(LossTypeEnum.REC_LOSS.getKey()) != null) {
                    Integer outRecNum = outLossTypeMap.get(LossTypeEnum.REC_LOSS.getKey()).size();
                    blockLossTypeGatherDTO.setOutRecNum(outRecNum);
                }
                if (outLossTypeMap.get(LossTypeEnum.CODE_LOSS.getKey()) != null) {
                    Integer outCodeNum = outLossTypeMap.get(LossTypeEnum.CODE_LOSS.getKey()).size();
                    blockLossTypeGatherDTO.setOutCodeNum(outCodeNum);
                }
                if (outLossTypeMap.get(LossTypeEnum.HOMEPAGE_LOSS.getKey()) != null) {
                    Integer outHomePageNum = outLossTypeMap.get(LossTypeEnum.HOMEPAGE_LOSS.getKey()).size();
                    blockLossTypeGatherDTO.setOutHomePageNum(outHomePageNum);
                }
            }
        }
        //内部丢失
        if (lossWayMap.get(LossWayEnum.IN_LOSS.getKey()) != null) {
            Integer inLossNum = lossWayMap.get(LossWayEnum.IN_LOSS.getKey()).size();
            blockLossTypeGatherDTO.setInLossNum(inLossNum);
            if (lossWayMap.get(LossWayEnum.IN_LOSS.getKey()) != null) {
                Map<String, List<BlocklossResult>> inLossTypeMap = EntityUtil.makeEntityListMap(lossWayMap.get(LossWayEnum.IN_LOSS.getKey()), "lossType");
                if (inLossTypeMap.get(LossTypeEnum.REC_LOSS.getKey()) != null) {
                    Integer inRecNum = inLossTypeMap.get(LossTypeEnum.REC_LOSS.getKey()).size();
                    blockLossTypeGatherDTO.setInRecNum(inRecNum);
                }
                if (inLossTypeMap.get(LossTypeEnum.CODE_LOSS.getKey()) != null) {
                    Integer inCodeNum = inLossTypeMap.get(LossTypeEnum.CODE_LOSS.getKey()).size();
                    blockLossTypeGatherDTO.setInCodeNum(inCodeNum);
                }
                if (inLossTypeMap.get(LossTypeEnum.HOMEPAGE_LOSS.getKey()) != null) {
                    Integer inHomePageNum = inLossTypeMap.get(LossTypeEnum.HOMEPAGE_LOSS.getKey()).size();
                    blockLossTypeGatherDTO.setInHomePageNum(inHomePageNum);
                }
            }
        }
        return blockLossTypeGatherDTO;
    }

    /**
     * 获取这段时间内his的数据量
     *
     * @param hisMedicalRecords
     * @Return java.lang.Integer
     */
    private Integer getHisMedicalRecordsCount(List<HisMedicalRecordDTO> hisMedicalRecords) {

        AtomicReference<Integer> num = new AtomicReference<>(0);
        if (ListUtil.isNotEmpty(hisMedicalRecords)) {
            hisMedicalRecords.stream().forEach(hisMedicalRecordDTO -> {
                //病历+1
                num.getAndSet(num.get() + 1);
                //病案首页+1
                if (StringUtil.isNotEmpty(hisMedicalRecordDTO.getHomePageId())) {
                    num.getAndSet(num.get() + 1);
                }
                //文书
                if (ListUtil.isNotEmpty(hisMedicalRecordDTO.getHisRecs())) {
                    num.getAndSet(num.get() + hisMedicalRecordDTO.getHisRecs().size());
                }

            });
        }
        return num.get();
    }

    /**
     * 数据补录
     *
     * @param dataRepariVO
     * @Return boolean
     */
    public boolean dataRepari(DataRepariVO dataRepariVO) {
        //调用数据补录服务

        return hisDataManagementFacade.dataRepari(dataRepariVO);
    }
}