package com.docus.server.report.job;

import com.alibaba.fastjson.JSONObject;
import com.docus.core.util.Func;
import com.docus.infrastructure.core.exception.BaseException;
import com.docus.infrastructure.redis.service.IdService;
import com.docus.infrastructure.redis.service.RedisOps;
import com.docus.infrastructure.web.api.CommonResult;
import com.docus.infrastructure.web.api.ResultCode;
import com.docus.server.collection.entity.TBasic;
import com.docus.server.collection.mapper.TBasicMapper;
import com.docus.server.report.api.ShunDePeopleService;
import com.docus.server.report.api.TaskDistributeService;
import com.docus.server.report.api.dto.*;
import com.docus.server.report.api.vo.SdRyBloodReportVO;
import com.docus.server.report.config.SdRyCollectNurseInsertSugarConfig;
import com.docus.server.report.config.SdRyReportQueryConfig;
import com.docus.server.report.config.TaskValidateConfig;
import com.docus.server.report.config.ZdAssortConfig;
import com.docus.server.report.consts.ReportDownloadWait;
import com.docus.server.report.entity.AfJobTime;
import com.docus.server.report.entity.AfReportRecord;
import com.docus.server.report.mapper.AfJobTimeMapper;
import com.docus.server.report.mapper.AfReportRecordMapper;
import com.docus.server.report.service.ReportService;
import com.docus.server.report.service.ShunDePeopleBusinessService;
import com.docus.server.report.util.TableJsonRead;
import com.docus.server.report.util.XmlUtil;
import com.docus.server.report.validate.CollectTaskValidation;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Node;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 报告相关xxl-Job
 *
 * @author jiashi
 */
@Component
@Slf4j
public class ReportJob {
    @Resource
    private ReportService reportService;
    @Resource
    private AfReportRecordMapper afReportRecordMapper;
    @Resource
    private TBasicMapper tBasicMapper;
    @Resource
    private AfJobTimeMapper afJobTimeMapper;
    @Resource
    private IdService idService;
    @Resource
    private SdRyReportQueryConfig sdRyReportQueryConfig;
    @Resource
    private TaskDistributeService taskDistributeService;
    @Resource
    private ShunDePeopleService shunDePeopleService;
    @Resource
    private ShunDePeopleBusinessService shunDePeopleBusinessService;
    @Resource
    RedisOps redisOps;
    @Value("${docus.report.waittime}")
    private int waittime;

    /**
     * 输血报告采集
     */
    @XxlJob("SdRyBloodCollectJob")
    public void sdRyBloodCollectJob() {
        String bloodCollectorId = sdRyReportQueryConfig.getBloodCollectorId();
        ReportDownTwoDto reportDownTwoDto = taskDistributeService.getNoViewTaskByCollectorId(bloodCollectorId);
        if (reportDownTwoDto == null) {
            return;
        }
        String patientId = reportDownTwoDto.getPatient().getPatientId();
        String inpatientNo = reportDownTwoDto.getPatient().getInpatientNo();
        Integer admissTimes = reportDownTwoDto.getHospitals().get(0).getAdmissTimes();
        Long taskId = reportDownTwoDto.getTasks().get(0).getTaskId();
        CommonResult<List<SdRyBloodReportVO>> bloodViewReport = shunDePeopleService.getBloodView(inpatientNo, admissTimes);
        List<SdRyBloodReportVO> sdRyBloodReportVOList = bloodViewReport.getData();
        if (ResultCode.SUCCESS.getCode().equals(bloodViewReport.getCode()) && Func.isNotEmpty(sdRyBloodReportVOList)) {
            ReportDto reportDto;
            for (SdRyBloodReportVO bloodReportVO : sdRyBloodReportVOList) {
                reportDto = new ReportDto();
                reportDto.setSysFlag(bloodCollectorId);
                reportDto.setTaskId(taskId);
                reportDto.setDownUrl(bloodReportVO.getFileUrl());
                reportDto.setFileTitle(bloodReportVO.getFileId() + bloodReportVO.getFileDesc());
                reportDto.setSerialnum(bloodReportVO.getFileId());
                reportDto.setAssortId(ZdAssortConfig.getZdAssortId(sdRyReportQueryConfig.getBloodDefaultAssortType()));
                reportDto.setAdmisstimes(admissTimes);
                reportDto.setInpatientNo(inpatientNo);
                reportDto.setPatientId(patientId);
                reportDto.setDowntype(1);
                reportDto.setFileSource("1");
                reportDto.setFilestoragetype("1");
                reportService.report(reportDto);
            }
        }
        log.info("病案号：{}，住院次数：{}，输血报告单采集：{} 份", inpatientNo, admissTimes, Func.isEmpty(sdRyBloodReportVOList) ? 0 : sdRyBloodReportVOList.size());
    }

    @XxlJob("SdRyLisCollectJob")
    public void sdRyLisCollectJob() {
        String reportQueryLisCollectorId = sdRyReportQueryConfig.getReportQueryLisCollectorId();
        ReportDownTwoDto reportDownTwoDto = taskDistributeService.getNoViewTaskByCollectorId(reportQueryLisCollectorId);
        if (reportDownTwoDto == null) {
            return;
        }
        String patientId = reportDownTwoDto.getPatient().getPatientId();
        List<TBasic> basicList = tBasicMapper.selectBasicListByPatientIds(Collections.singletonList(patientId));
        if (basicList.isEmpty()) {
            log.warn("patientId {} 未找到基础数据！", patientId);
        }
        List<ReportDto> reportDtoList = collectLisReport(basicList.get(0));

        reportDtoList.forEach(reportDto -> {
            reportDto.setSysFlag(reportQueryLisCollectorId);
            reportDto.setTaskId(reportDownTwoDto.getTasks().get(0).getTaskId());
            reportService.report(reportDto);
        });

    }

    /**
     * 门诊检查报告查询
     */
    @XxlJob("SdRyMzInspectCollectJob")
    public void sdRyMzInspectCollectJob() {
        String reportQueryMzInspectCollectorId = sdRyReportQueryConfig.getReportQueryMzInspectCollectorId();
        ReportDownTwoDto reportDownTwoDto = taskDistributeService.getNoViewTaskByCollectorId(reportQueryMzInspectCollectorId);
        if (reportDownTwoDto == null) {
            return;
        }
        String patientId = reportDownTwoDto.getPatient().getPatientId();
        List<TBasic> basicList = tBasicMapper.selectBasicListByPatientIds(Collections.singletonList(patientId));
        if (basicList.isEmpty()) {
            log.warn("patientId {} 未找到基础数据！", patientId);
        }
        List<ReportDto> reportDtoList = collectMzInspectReport(basicList.get(0));

        reportDtoList.forEach(reportDto -> {
            reportDto.setSysFlag(reportQueryMzInspectCollectorId);
            reportDto.setTaskId(reportDownTwoDto.getTasks().get(0).getTaskId());
            reportService.report(reportDto);
        });

    }

    /**
     * 住院检查报告查询
     */
    @XxlJob("SdRyZyInspectCollectJob")
    public void sdRyZyInspectCollectJob() {
        String reportQueryZyInspectCollectorId = sdRyReportQueryConfig.getReportQueryZyInspectCollectorId();
        ReportDownTwoDto reportDownTwoDto = taskDistributeService.getNoViewTaskByCollectorId(reportQueryZyInspectCollectorId);
        if (reportDownTwoDto == null) {
            return;
        }
        String patientId = reportDownTwoDto.getPatient().getPatientId();
        List<TBasic> basicList = tBasicMapper.selectBasicListByPatientIds(Collections.singletonList(patientId));
        if (basicList.isEmpty()) {
            log.warn("patientId {} 未找到基础数据！", patientId);
        }
        List<ReportDto> reportDtoList = collectZyInspectReport(basicList.get(0));
        // 是否是宝宝的病案，如果是，报告需要给母亲的信息
        if (isBabyTask(reportDownTwoDto)) {
            PatientInfoDTO parent = reportDownTwoDto.getParent();
            for (ReportDto reportDto : reportDtoList) {
                reportDto.setPatientId(parent.getPatientId());
                reportDto.setInpatientNo(parent.getInpatientNo());
                reportDto.setAdmisstimes(parent.getAdmissTimes());
                reportDto.setJzh(parent.getJzh());
            }
        }
        reportDtoList.forEach(reportDto -> {
            reportDto.setSysFlag(reportQueryZyInspectCollectorId);
            reportDto.setTaskId(reportDownTwoDto.getTasks().get(0).getTaskId());
            reportService.report(reportDto);
        });

    }

    private boolean isBabyTask(ReportDownTwoDto reportDownTwoDto) {
        String inpatientNo = reportDownTwoDto.getPatient().getInpatientNo();
        return inpatientNo != null && inpatientNo.toUpperCase().contains("B") && reportDownTwoDto.getParent() != null;
    }

    /**
     * 顺德人医移动护理报告采集任务
     */
    @XxlJob("SdRyNurseInsertSugarCollectJob")
    public void sdRyNurseInsertSugarCollectJob() {
        String reportQueryNurseInsertSugarCollectorId = sdRyReportQueryConfig.getReportQueryNurseInsertSugarCollectorId();
        ReportDownTwoDto reportDownTwoDto = taskDistributeService.getNoViewTaskByCollectorId(reportQueryNurseInsertSugarCollectorId);
        if (reportDownTwoDto == null) {
            return;
        }
        if (isCancelTask(reportDownTwoDto, reportQueryNurseInsertSugarCollectorId)) {
            log.warn("作废任务，{}", reportDownTwoDto);
            taskDistributeService.cancel(reportDownTwoDto.getTasks().get(0).getTaskId());
            return;
        }
        boolean babyTask = isBabyTask(reportDownTwoDto);
        String patientId = reportDownTwoDto.getPatient().getPatientId();
        String inpatientNo = reportDownTwoDto.getPatient().getInpatientNo();
        Integer admissTimes = reportDownTwoDto.getHospitals().get(0).getAdmissTimes();
        final String traceCode = "nurse_print_doc";
        SdNurseInsertSugarRequest sdNurseInsertSugarRequest = new SdNurseInsertSugarRequest(inpatientNo, admissTimes.toString(), traceCode);
        SdNurseInsertSugarResponse sdNurseInsertSugarResponse = shunDePeopleService.getNurseInsertSugarReport(sdNurseInsertSugarRequest);
        List<SdNurseInsertSugarResponse.NisData> nurseInsertSugarReportList = sdNurseInsertSugarResponse.getData();

        if (Func.isNotEmpty(nurseInsertSugarReportList)) {
            Integer filesNumber = nurseInsertSugarReportList.get(0).getFILES_NUMBER();
            Integer nurseFileCount = tBasicMapper.getNurseFileCount(patientId);
            if (filesNumber == null) {
                log.warn("{} ,{},接口未返回文件数量！", inpatientNo, admissTimes);
                return;
            }
            if (nurseFileCount == null) {
                log.warn("{} , {},未获取到护理提交的文件数量！", inpatientNo, admissTimes);
                shunDePeopleBusinessService.nurseFileCountError(inpatientNo, admissTimes, "未获取到护理提交的文件数量!");
                return;
            }
            if (!filesNumber.equals(nurseFileCount)) {
                log.warn("{} , {},护理提交的文件数量与接口返回的文件数量不匹配！", inpatientNo, admissTimes);
                shunDePeopleBusinessService.nurseFileCountError(inpatientNo, admissTimes, "护理提交的文件数量与接口返回的文件数量不匹配");
                return;
            }
            // 从配置获取需要过滤的文件名称
            SdRyCollectNurseInsertSugarConfig config = SdRyCollectNurseInsertSugarConfig.getConfig();
            List<String> fileRemoveByFormName = config.getFileRemoveByFormName();
            List<SdNurseInsertSugarResponse.NisData> removeFiles = nurseInsertSugarReportList.stream()
                    .filter(item -> isCharacterContains(item.getForm_name(), fileRemoveByFormName))
                    .collect(Collectors.toList());
            log.info("住院号：{},住院次数{}，护理采集过滤文件： {} 共 {} 条", inpatientNo, admissTimes, fileRemoveByFormName, removeFiles.size());
            tBasicMapper.saveNisRemoveFilesCount(patientId, removeFiles.size());

            ReportDto reportDto;
            int collectFileCount = 0;
            for (SdNurseInsertSugarResponse.NisData nisReport : nurseInsertSugarReportList) {
                // 从过滤配置中匹配，如果匹配则跳过本次循环
                if (isCharacterContains(nisReport.getForm_name(), fileRemoveByFormName)) {
                    continue;
                }
                reportDto = new ReportDto();
                reportDto.setSysFlag(reportQueryNurseInsertSugarCollectorId);
                reportDto.setTaskId(reportDownTwoDto.getTasks().get(0).getTaskId());
                reportDto.setDownUrl(nisReport.getUrl());
                reportDto.setFileTitle(nisReport.getForm_name());
                reportDto.setSerialnum(nisReport.getForm_id());
                reportDto.setAssortId(ZdAssortConfig.getZdAssortId(nisReport.getForm_name(), sdRyReportQueryConfig.getReportQueryNurseInsertSugarDefaultAssortType()));
                reportDto.setAdmisstimes(admissTimes);
                reportDto.setInpatientNo(inpatientNo);
                reportDto.setPatientId(patientId);
                reportDto.setDowntype(1);
                reportDto.setFileSource("1");
                reportDto.setFilestoragetype("1");
                if (babyTask) {
                    // 婴儿任务，文件传到母亲病案,来源加后缀
                    PatientInfoDTO parent = reportDownTwoDto.getParent();
                    reportDto.setAdmisstimes(parent.getAdmissTimes());
                    reportDto.setInpatientNo(parent.getInpatientNo());
                    reportDto.setPatientId(parent.getPatientId());
                    reportDto.setSysFlag(reportQueryNurseInsertSugarCollectorId+SdRyReportQueryConfig.BABY_COLLECTOR_ID_SUFFIX);
                }
                reportService.report(reportDto);
                collectFileCount++;
            }
            log.info("住院号：{},住院次数{}，护理采集文件：  {} 条", inpatientNo, admissTimes, collectFileCount);
            if (babyTask) {
                return;
            }
            // 设置一个redisKey,过期被监听处理
            String redisKey = String.format(ReportDownloadWait.REPORT_DOWNLOAD_WAIT_KEY, reportQueryNurseInsertSugarCollectorId, patientId);
            redisOps.setEx(redisKey, "0", waittime * 60);
        }
    }

    /**
     * 循环遍历 集合，如果 str字符串包含有集合中的元素，返回true；
     */
    private static boolean isCharacterContains(String str, List<String> strList) {
        for (String e : strList) {
            if (str.contains(e)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 判断是否是需要作废的病案
     *
     * @param taskDTO
     * @param collectorId
     * @return
     */
    private boolean isCancelTask(ReportDownTwoDto taskDTO, String collectorId) {
        TaskValidateConfig.CollectTaskConfig collectTaskConfig = TaskValidateConfig.getCollectTaskConfig(collectorId);
        if (collectTaskConfig != null && Func.isNotEmpty(collectTaskConfig.getCancel())) {
            // 满足其中一个即可
            for (TaskValidateConfig.CollectTaskFilterConfig cancelCollectTaskConfig : collectTaskConfig.getCancel()) {
                if (isCancelTask(taskDTO, cancelCollectTaskConfig)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isCancelTask(ReportDownTwoDto taskDTO, TaskValidateConfig.CollectTaskFilterConfig cancelCollectTaskConfig) {
        TaskValidateConfig.ValidateConfig admissionDateConfig = cancelCollectTaskConfig.getAdmissionDate();
        TaskValidateConfig.ValidateConfig dischargeDateConfig = cancelCollectTaskConfig.getDischargeDate();
        TaskValidateConfig.ValidateConfig amissionDepartmentConfig = cancelCollectTaskConfig.getAdmissionDepartment();
        TaskValidateConfig.ValidateConfig dischargeDepartmenConfig = cancelCollectTaskConfig.getDischargeDepartment();
        CollectTaskValidation validation;
        // 是否验证了,每个验证不通过都会返回，记录是否进入了验证，进入了且验证未返回，代表全部通过了，改变标记为true返回。
        boolean validated = false;
        // 验证入院时间
        if (admissionDateConfig != null && admissionDateConfig.isEffective()) {
            validated = true;
            validation = new CollectTaskValidation.CollectTaskAdmissionDateValidation();
            CollectTaskValidation.ValidationResult validationResult = validation.validate(taskDTO.getHospitals().get(0).getAdmissDate(), admissionDateConfig);
            if (validationResult.getCode() == ResultCode.FAILED) {
                return false;
            }
        }
        // 验证出院时间
        if (dischargeDateConfig != null && dischargeDateConfig.isEffective()) {
            validated = true;
            validation = new CollectTaskValidation.CollectTaskDischargeDateValidation();
            CollectTaskValidation.ValidationResult validationResult = validation.validate(taskDTO.getHospitals().get(0).getDisDate(), dischargeDateConfig);
            if (validationResult.getCode() == ResultCode.FAILED) {
                return false;
            }
        }
        // 验证入院科室
        if (amissionDepartmentConfig != null && amissionDepartmentConfig.isEffective()) {
            validated = true;
            validation = new CollectTaskValidation.CollectTaskAdmissionDepartmentValidation();
            CollectTaskValidation.ValidationResult validationResult = validation.validate(taskDTO.getHospitals().get(0).getAdmissDeptName(), amissionDepartmentConfig);
            if (validationResult.getCode() == ResultCode.FAILED) {
                return false;
            }
        }
        // 验证出院科室
        if (dischargeDepartmenConfig != null && dischargeDepartmenConfig.isEffective()) {
            validated = true;
            validation = new CollectTaskValidation.CollectTaskDischargeDepartmentValidation();
            CollectTaskValidation.ValidationResult validationResult = validation.validate(taskDTO.getHospitals().get(0).getDisDeptName(), dischargeDepartmenConfig);
            if (validationResult.getCode() == ResultCode.FAILED) {
                return false;
            }
        }

        return validated;
    }

    private void validateAdmissionDate(String admissDate, String collectorId) {
        if (Func.isBlank(admissDate)) {
            throw new BaseException("任务患者出院时间为空！");
        }
        LocalDateTime admissDateTime = Func.parseDateTime(admissDate);


    }


    public List<ReportDto> collectLisReport(TBasic tBasic) {
        List<ReportDto> reportDtoList = getLisReportList(tBasic);
        if (reportDtoList.isEmpty()) {
            log.warn("病案主键 patientId {} 未查询 LIS 检验报告！", tBasic.getPatientId());
        }
        return reportDtoList;
    }


    public List<ReportDto> collectMzInspectReport(TBasic basic) {
        List<ReportDto> reportDtoList = getMzInspectReportList(basic);
        if (reportDtoList.isEmpty()) {
            log.warn("病案主键 patientId {} 未查询  检查（门诊）报告！", basic.getPatientId());
        }
        return reportDtoList;
    }

    public List<ReportDto> collectZyInspectReport(TBasic basic) {
        List<ReportDto> reportDtoList = getZyInspectReportList(basic);
        if (reportDtoList.isEmpty()) {
            log.warn("病案主键 patientId {} 未查询  检查（住院）报告！", basic.getPatientId());
        }
        return reportDtoList;
    }


    public void queryLisReport(List<TBasic> basicList) {
        for (TBasic tBasic : basicList) {
            List<ReportDto> reportDtoList = getLisReportList(tBasic);
            if (reportDtoList.isEmpty()) {
                log.warn("病案主键 patientId {} 未查询 LIS 检验报告！", tBasic.getPatientId());
                continue;
            }
            reportDtoList.forEach(reportDto -> {
                reportService.report(reportDto);
            });
        }
    }


    private List<ReportDto> getZyInspectReportList(TBasic tBasic) {

        String sDryIndex = tBasicMapper.getSdRyIndexByPatientId(tBasic.getPatientId());
        if (Func.isNotBlank(sDryIndex)) {
            sDryIndex = sDryIndex.replace("m", "")
                    .replace("z", "");
            return getZyInspectReportBySdRyJxId(sDryIndex, tBasic);
        } else {
            log.warn("patientId :{},未保存索引信息", tBasic.getPatientId());
            return new ArrayList<>();
        }
    }

    private List<ReportDto> getMzInspectReportList(TBasic tBasic) {
        // 根据基础信息查顺德报告业务系统索引，查 交叉索引
        List<String> sdRyMzReportPatientIds = getSdRyZyReportPatientIds(tBasic.getPatientId());
        if (sdRyMzReportPatientIds.isEmpty()) {
            log.warn("patientId：{} 未查询到门诊检查报告患者交叉索引", tBasic.getPatientId());
            return new ArrayList<>();
        } else {
            List<ReportDto> reportDtoList = new ArrayList<>();
            // 根据门诊交叉索引查询报告
            for (String mzSdRyReportPatientId : sdRyMzReportPatientIds) {
                List<ReportDto> reportDtoList2 = getMzInspectReportBySdRyJxId(mzSdRyReportPatientId, tBasic);
                reportDtoList.addAll(reportDtoList2);
            }
            return reportDtoList;
        }

    }

    private List<ReportDto> getInspectReportBySdRyJxId(String sdRyReportPatientId, TBasic tBasic) {
        List<ReportDto> list = new ArrayList<>();
        List<ReportDto> mzInspectReportBySdRyJxId = getMzInspectReportBySdRyJxId(sdRyReportPatientId, tBasic);
        List<ReportDto> zyInspectReportBySdRyJxId = getZyInspectReportBySdRyJxId(sdRyReportPatientId, tBasic);
        list.addAll(mzInspectReportBySdRyJxId);
        list.addAll(zyInspectReportBySdRyJxId);
        return list;
    }

    private List<ReportDto> getMzInspectReportBySdRyJxId(String sdRyReportPatientId, TBasic tBasic) {
        try {
            List<ReportDto> reportDtos = new ArrayList<>();
            int pageNum = 1;
            final int pageSize = 5;
            // 报告接口返回的总数
            AtomicInteger reportTotalCount = new AtomicInteger(0);
            // 已经查询的条数
            int alreadyQrCount = 0;
            do {
                Date admissDate = tBasic.getAdmissDate();
                Date disDate = tBasic.getDisDate();
                if (admissDate == null || disDate == null) {
                    throw new BaseException("patientId：" + tBasic.getPatientId() + "的入院时间为空");
                }
                ZoneId zoneId = ZoneId.systemDefault();
                Instant adminssDateInstant = admissDate.toInstant();
                Instant disDateInstant = disDate.toInstant();
                // 开始时间去入院前三天
                LocalDate admissLocalDate = adminssDateInstant.atZone(zoneId).toLocalDate();
                LocalDate startTimeLocalDate = admissLocalDate.plusDays(-3);
                LocalDate disLocalDate = disDateInstant.atZone(zoneId).toLocalDate();
                String startTime = startTimeLocalDate.toString() + " 00:00:00";
                String endTime = disLocalDate.toString() + " 23:59:59";

                SdJxReportDto sdJxReportDto = new SdJxReportDto();
                sdJxReportDto.setPage(true);
                sdJxReportDto.setPageNo(pageNum);
                sdJxReportDto.setPageSize(pageSize);
                sdJxReportDto.setPatientId(sdRyReportPatientId);
                sdJxReportDto.setStartTime(startTime);
                sdJxReportDto.setEndTime(endTime);
                sdJxReportDto.setPatentTypeCode("1");
                sdJxReportDto.setOrgCode("4560886379");
                String respBody = shunDePeopleService.getInspectReportByJxId(sdJxReportDto);
                alreadyQrCount += pageSize;
                List<ReportDto> reportDtoList = parseQuerySdRyInspectReport(respBody, tBasic, reportTotalCount);
                reportDtos.addAll(reportDtoList);
                // 解析之后，总数已经赋值了，判断已经查询的数量是否已经满足总数
                if (reportTotalCount.get() == 0 || alreadyQrCount >= reportTotalCount.get()) {
                    break;
                }
                pageNum++;
            } while (true);
            return reportDtos;
        } catch (Exception ex) {
            log.error("查询门诊检查报告出错啦！", ex);
            return new ArrayList<>();
        }
    }

    private List<ReportDto> getZyInspectReportBySdRyJxId(String sdRyReportPatientId, TBasic tBasic) {
        try {
            List<ReportDto> reportDtos = new ArrayList<>();
            int pageNum = 1;
            final int pageSize = 5;
            // 报告接口返回的总数
            AtomicInteger reportTotalCount = new AtomicInteger(0);
            // 已经查询的条数
            int alreadyQrCount = 0;
            Integer admissTimes = tBasic.getAdmissTimes();
            Date admissDate = tBasic.getAdmissDate();
            Date disDate = tBasic.getDisDate();
            if (admissDate == null || disDate == null) {
                throw new BaseException("patientId：" + tBasic.getPatientId() + "的入院时间为空");
            }
            ZoneId zoneId = ZoneId.systemDefault();
            Instant adminssDateInstant = admissDate.toInstant();
            Instant disDateInstant = disDate.toInstant();
            // 开始时间去入院前三天
            LocalDate admissLocalDate = adminssDateInstant.atZone(zoneId).toLocalDate();
            LocalDate startTimeLocalDate = admissLocalDate.plusDays(-3);
            LocalDate disLocalDate = disDateInstant.atZone(zoneId).toLocalDate();
            String startTime = startTimeLocalDate.toString() + " 00:00:00";
            String endTime = disLocalDate.toString() + " 23:59:59";
            do {
                SdJxReportDto sdJxReportDto = new SdJxReportDto();
                sdJxReportDto.setPage(true);
                sdJxReportDto.setPageNo(pageNum);
                sdJxReportDto.setPageSize(pageSize);
                sdJxReportDto.setPatientId(sdRyReportPatientId);
                sdJxReportDto.setStartTime(startTime);
                sdJxReportDto.setEndTime(endTime);
                sdJxReportDto.setPatentTypeCode("3");
                sdJxReportDto.setOrgCode("4560886379");
                String respBody = shunDePeopleService.getInspectReportByJxId(sdJxReportDto);
                alreadyQrCount += pageSize;
                List<ReportDto> reportDtoList = parseQuerySdRyInspectReport(respBody, tBasic, reportTotalCount);
                // 住院次数不是本次的，不需要
                reportDtoList = reportDtoList.stream().filter(t -> admissTimes.equals(getAdmissTimes(t.getVisitSn(), t.getPatientSn()))).collect(Collectors.toList());
                reportDtos.addAll(reportDtoList);
                // 解析之后，总数已经赋值了，判断已经查询的数量是否已经满足总数
                if (reportTotalCount.get() == 0 || alreadyQrCount >= reportTotalCount.get()) {
                    break;
                }
                pageNum++;
            } while (true);
            return reportDtos;
        } catch (Exception ex) {
            log.error("查询住院检查报告出错啦！", ex);
            return new ArrayList<>();
        }
    }

    /**
     * @param visitSn   住院号_住院次数
     * @param patientSn 患者id
     * @return 就诊次数
     */
    private static Integer getAdmissTimes(String visitSn, String patientSn) {
        String[] split = visitSn.split("_");
        return Integer.valueOf(split[1]);
    }

    private List<ReportDto> parseQuerySdRyInspectReport(String respBody, TBasic tBasic, AtomicInteger reportTotalCount) {
        JSONObject jsonObject = Func.readJson(respBody, JSONObject.class);
        Object resultCode = jsonObject.get("ResultCode");
        String successCode = "0";
        if (!successCode.equals(String.valueOf(resultCode))) {
            return new ArrayList<>();
        }
        try {
            Object countObj = jsonObject.get("count");
            if (countObj != null) {
                int count = Integer.parseInt(countObj.toString());
                reportTotalCount.set(count);
            }
        } catch (Exception ex) {
            log.error("解析count出错了！", ex);
        }
        TableJsonRead jsonRead = new TableJsonRead();
        SdPacsServerConfig config = jsonRead.Read("data-config", "sdry-pacs-server.json", SdPacsServerConfig.class);
        try {
            Object data = jsonObject.get("data");
            String dataJsonStr = Func.toJson(data);
            // 是否是json object ，因为返回的如果是 [] ，则不会识别为jsonObject
            List<ReportDto> reportDtoList = new ArrayList<>();
            if (Func.isJsonObject(dataJsonStr)) {
                JSONObject dataJsonObject = Func.readJson(dataJsonStr, JSONObject.class);
                Object result = dataJsonObject.get("result");
                String resultJsonStr = Func.toJson(result);
                List<JSONObject> reportObjectList = Func.parseJsonArray(resultJsonStr, JSONObject.class);
                if (Func.isNotEmpty(reportObjectList)) {
                    for (JSONObject reportObject : reportObjectList) {
                        // 系统修改
                        String updateBy = String.valueOf(reportObject.get("UPDATEBY"));
                        if (config != null && Func.isNotBlank(config.getHandlerSystem())) {
                            String handlerSystem = config.getHandlerSystem().toLowerCase();
                            List<String> handlerSystems = Arrays.asList(handlerSystem.split(","));
                            if (!handlerSystems.contains(updateBy.toLowerCase())) {
                                continue;
                            }
                        } else {
                            continue;
                        }

                        // 检查报告号
                        String examReportSn = String.valueOf(reportObject.get("EXAM_REPORT_SN"));
                        // 申请单号
                        String requestSn = String.valueOf(reportObject.get("REQUEST_SN"));
                        // pdf地址
                        String pdfUrl = String.valueOf(reportObject.get("FILE_PATH"));
                        // 报告名称
                        String reportName = String.valueOf(reportObject.get("REPORT_NAME"));

                        // 患者本次就诊唯一键：患者id【12位】+就诊次数
                        String visitSn = String.valueOf(reportObject.get("VISIT_SN"));
                        // 患者id
                        String patientSn = String.valueOf(reportObject.get("PATIENT_SN"));

                        ReportDto reportDto = new ReportDto();
                        reportDto.setAdmisstimes(tBasic.getAdmissTimes());
                        reportDto.setInpatientNo(tBasic.getInpatientNo());
                        // 确定报告唯一 报告单号+申请单号
                        reportDto.setSerialnum(examReportSn + requestSn);
                        reportDto.setFileTitle(reportName);
                        reportDto.setVisitSn(visitSn);
                        reportDto.setPatientSn(patientSn);

                        // 检查报告需要从Pacs接口获取base64
                        String[] split = examReportSn.split("_");
                        String fromPacs = shunDePeopleService.getBase64PdfFromPacs(split[0], split[1]);
                        // 从pacs打印出来
                        String base64 = parsePacsGetBase64(fromPacs);
                        if (Func.isBlank(base64)) {
                            continue;
                        }
                        String url = saveBase64(base64);
                        reportDto.setDownUrl(url);
                        reportDto.setDowntype(5);
                        // 根据系统来分类
                        reportDto.setAssortId(ZdAssortConfig.getZdAssortId(updateBy));
                        reportDto.setSysFlag(updateBy);
                        reportDto.setFileSource("1");
                        reportDto.setFilestoragetype("1");
                        reportDtoList.add(reportDto);
                    }
                }
            }
            return reportDtoList;
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            return new ArrayList<>();
        }
    }


    public String saveBase64(String base64) {
        String dir = createBase64SaveDir();
        String base64File = dir + File.separator + idService.getDateSeq() + ".txt";
        try (FileWriter fileWriter = new FileWriter(base64File);
             BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
            bufferedWriter.write(base64);
            bufferedWriter.flush();
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            return null;
        }
        return base64File;
    }

    private static String createBase64SaveDir() {
        try {
            File current = new File(".");
            String canonicalPath = current.getCanonicalPath();
            String dirPath = canonicalPath + File.separator + "base64" + File.separator + Func.formatDate(new Date());
            File dirFile = new File(dirPath);
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            return dirPath;
        } catch (Exception e) {
            String temp = "C:\\docus\\base64\\" + Func.formatDate(new Date());
            File file1 = new File(temp);
            if (!file1.exists()) {
                file1.mkdirs();
            }
            return temp;
        }
    }

    public String parsePacsGetBase64(String xml) {
        try {
            XmlUtil xmlUtil = XmlUtil.of(xml);
            Node codeNode = xmlUtil.getNode("/Result/Code");
            if ("0".equals(codeNode.getTextContent())) {
                Node base64Node = xmlUtil.getNode("/Result/Base64");
                return base64Node.getTextContent();
            }
        } catch (Exception ex) {
            log.error("解析pacs返回的base64信息失败：" + ex.getMessage(), ex);
            return null;
        }
        return null;
    }


    private List<ReportDto> getLisReportList(TBasic tBasic) {
        // 根据基础信息查顺德报告业务系统索引，查 交叉索引
        List<String> sdRyMzReportPatientIds = getSdRyZyReportPatientIds(tBasic.getPatientId());
        if (sdRyMzReportPatientIds.isEmpty()) {
            log.warn("patientId：{} 未查询到门诊Lis检验报告患者交叉索引", tBasic.getPatientId());
            return new ArrayList<>();
        }
        List<ReportDto> reportDtoList = new ArrayList<>();
        // 根据交叉索引查询报告
        for (String sdRyReportPatientId : sdRyMzReportPatientIds) {
            List<ReportDto> reportDtoList2 = getLisReportBySdRyJxId(sdRyReportPatientId, tBasic);
            reportDtoList.addAll(reportDtoList2);
        }
        return reportDtoList;
    }


    private List<ReportDto> getLisReportBySdRyJxId(String sdRyReportPatientId, TBasic tBasic) {
        List<ReportDto> list = new ArrayList<>();
//        List<ReportDto> zyLisReportBySdRyJxId = getZyLisReportBySdRyJxId(sdRyReportPatientId, tBasic);
        List<ReportDto> mzLisReportBySdRyJxId = getMzLisReportBySdRyJxId(sdRyReportPatientId, tBasic);
        list.addAll(mzLisReportBySdRyJxId);
//        list.addAll(zyLisReportBySdRyJxId);
        return list;
    }

    /**
     * 获取住院的检验报告
     */
    private List<ReportDto> getZyLisReportBySdRyJxId(String sdRyReportPatientId, TBasic tBasic) {
        try {
            List<ReportDto> reportDtos = new ArrayList<>();
            int pageNum = 1;
            final int pageSize = 5;

            // 报告接口返回的总数
            AtomicInteger reportTotalCount = new AtomicInteger(0);
            // 已经查询的条数
            int alreadyQrCount = 0;
            do {
                Date admissDate = tBasic.getAdmissDate();
                Date disDate = tBasic.getDisDate();
                if (admissDate == null || disDate == null) {
                    throw new BaseException("patientId：" + tBasic.getPatientId() + "的入院时间为空");
                }
                ZoneId zoneId = ZoneId.systemDefault();
                Instant adminssDateInstant = admissDate.toInstant();
                Instant disDateInstant = disDate.toInstant();
                // 开始时间去入院前三天
                LocalDate admissLocalDate = adminssDateInstant.atZone(zoneId).toLocalDate();
                LocalDate startTimeLocalDate = admissLocalDate.plusDays(-3);
                LocalDate disLocalDate = disDateInstant.atZone(zoneId).toLocalDate();
                String startTime = startTimeLocalDate.toString() + " 00:00:00";
                String endTime = disLocalDate.toString() + " 23:59:59";

                SdJxReportDto sdJxReportDto = new SdJxReportDto();
                sdJxReportDto.setPage(true);
                sdJxReportDto.setPageNo(pageNum);
                sdJxReportDto.setPageSize(pageSize);
                sdJxReportDto.setPatientId(sdRyReportPatientId);
                sdJxReportDto.setStartTime(startTime);
                sdJxReportDto.setEndTime(endTime);
                sdJxReportDto.setPatentTypeCode("3");
                sdJxReportDto.setOrgCode("4560886379");
                String respBody = shunDePeopleService.getLisReportByJxId(sdJxReportDto);
                alreadyQrCount += pageSize;
                List<ReportDto> reportDtoList = parseQuerySdRyLisReport(respBody, tBasic, reportTotalCount);
                reportDtos.addAll(reportDtoList);
                // 解析之后，总数已经赋值了，判断已经查询的数量是否已经满足总数
                if (reportTotalCount.get() == 0 || alreadyQrCount >= reportTotalCount.get()) {
                    break;
                }

                pageNum++;
            } while (true);
            return reportDtos;
        } catch (Exception ex) {
            log.error("查询Lis报告出错啦！", ex);
            return new ArrayList<>();
        }
    }

    /**
     * 获取门诊的检验报告
     */
    private List<ReportDto> getMzLisReportBySdRyJxId(String sdRyReportPatientId, TBasic tBasic) {
        try {
            List<ReportDto> reportDtos = new ArrayList<>();
            int pageNum = 1;
            final int pageSize = 5;
            // 报告接口返回的总数
            AtomicInteger reportTotalCount = new AtomicInteger(0);
            // 已经查询的条数
            int alreadyQrCount = 0;
            do {
                Date admissDate = tBasic.getAdmissDate();
                Date disDate = tBasic.getDisDate();
                if (admissDate == null || disDate == null) {
                    throw new BaseException("patientId：" + tBasic.getPatientId() + "的入院时间为空");
                }
                ZoneId zoneId = ZoneId.systemDefault();
                Instant adminssDateInstant = admissDate.toInstant();
                Instant disDateInstant = disDate.toInstant();
                // 开始时间去入院前三天
                LocalDate admissLocalDate = adminssDateInstant.atZone(zoneId).toLocalDate();
                LocalDate startTimeLocalDate = admissLocalDate.plusDays(-3);
                LocalDate disLocalDate = disDateInstant.atZone(zoneId).toLocalDate();
                String startTime = startTimeLocalDate.toString() + " 00:00:00";
                String endTime = disLocalDate.toString() + " 23:59:59";

                SdJxReportDto sdJxReportDto = new SdJxReportDto();
                sdJxReportDto.setPage(true);
                sdJxReportDto.setPageNo(pageNum);
                sdJxReportDto.setPageSize(pageSize);
                sdJxReportDto.setPatientId(sdRyReportPatientId);
                sdJxReportDto.setStartTime(startTime);
                sdJxReportDto.setEndTime(endTime);
                sdJxReportDto.setPatentTypeCode("1");
                sdJxReportDto.setOrgCode("4560886379");

                String respBody = shunDePeopleService.getLisReportByJxId(sdJxReportDto);
                alreadyQrCount += pageSize;
                List<ReportDto> reportDtoList = parseQuerySdRyLisReport(respBody, tBasic, reportTotalCount);
                reportDtos.addAll(reportDtoList);
                // 解析之后，总数已经赋值了，判断已经查询的数量是否已经满足总数
                if (reportTotalCount.get() == 0 || alreadyQrCount >= reportTotalCount.get()) {
                    break;
                }
                pageNum++;
            } while (true);
            return reportDtos;
        } catch (Exception ex) {
            log.error("查询Lis报告出错啦！", ex);
            return new ArrayList<>();
        }
    }

    private List<ReportDto> parseQuerySdRyLisReport(String respBody, TBasic tBasic, AtomicInteger reportTotalCount) {
        JSONObject jsonObject = Func.readJson(respBody, JSONObject.class);
        Object resultCode = jsonObject.get("ResultCode");
        String successCode = "0";
        if (!successCode.equals(String.valueOf(resultCode))) {
            return new ArrayList<>();
        }
        try {
            Object countObj = jsonObject.get("count");
            if (countObj != null) {
                int count = Integer.parseInt(countObj.toString());
                reportTotalCount.set(count);
            }
        } catch (Exception ex) {
            log.error("解析count出错了！", ex);
        }
        try {
            Object data = jsonObject.get("data");
            String dataJsonStr = Func.toJson(data);
            // 是否是json object ，因为返回的如果是 [] ，则不会识别为jsonObject
            List<ReportDto> reportDtoList = new ArrayList<>();
            if (Func.isJsonObject(dataJsonStr)) {
                JSONObject dataJsonObject = Func.readJson(dataJsonStr, JSONObject.class);
                Object result = dataJsonObject.get("result");
                String resultJsonStr = Func.toJson(result);
                List<JSONObject> reportObjectList = Func.parseJsonArray(resultJsonStr, JSONObject.class);
                if (Func.isNotEmpty(reportObjectList)) {
                    for (JSONObject reportObject : reportObjectList) {
                        // 检验报告号
                        String labReportSn = String.valueOf(reportObject.get("LAB_REPORT_SN"));
                        // 申请单号
                        String requestSn = String.valueOf(reportObject.get("REQUEST_SN"));
                        // pdf地址
                        String pdfUrl = String.valueOf(reportObject.get("PDF_URL"));
                        // 报告名称
                        String reportTypeName = String.valueOf(reportObject.get("REPORT_TYPE_NAME"));
                        // 系统修改
                        String updateBy = String.valueOf(reportObject.get("UPDATEBY"));

                        ReportDto reportDto = new ReportDto();
                        reportDto.setAdmisstimes(tBasic.getAdmissTimes());
                        reportDto.setInpatientNo(tBasic.getInpatientNo());
                        // 确定报告唯一 报告单号+申请单号
                        reportDto.setSerialnum(labReportSn + requestSn);
                        reportDto.setFileTitle(reportTypeName);
                        reportDto.setDownUrl(pdfUrl);
                        // 根据系统来分类
                        reportDto.setAssortId(ZdAssortConfig.getZdAssortId(updateBy));
                        reportDto.setSysFlag(updateBy);
                        reportDto.setFileSource("1");
                        reportDto.setFilestoragetype("1");
                        reportDtoList.add(reportDto);
                    }
                }
            }
            return reportDtoList;
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            return new ArrayList<>();
        }
    }


    /**
     * 根据归档病案主键查询门诊报告交叉索引
     *
     * @param patientId 归档病案主键
     * @return 门诊报告交叉索引
     */
    private List<String> getSdRyMzReportPatientIds(String patientId) {
        try {
            String sDryIndex = tBasicMapper.getSdRyIndexByPatientId(patientId);
            if (Func.isBlank(sDryIndex)) {
                log.warn("归档系统 patientId:{} 未关联到第三方索引", patientId);
                return new ArrayList<>();
            }
            return shunDePeopleService.getSdRyMzReportJxIds(sDryIndex);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            return new ArrayList<>();
        }
    }

    /**
     * 根据归档病案主键查询住院报告交叉索引
     *
     * @param patientId 归档病案主键
     * @return 住院报告交叉索引
     */
    private List<String> getSdRyZyReportPatientIds(String patientId) {
        try {
            String sDryIndex = tBasicMapper.getSdRyIndexByPatientId(patientId);
            if (Func.isBlank(sDryIndex)) {
                log.warn("归档系统 patientId:{} 未关联到第三方索引", patientId);
                return new ArrayList<>();
            }
            return shunDePeopleService.getSdRyZyReportJxIds(sDryIndex);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            return new ArrayList<>();
        }
    }

    private void refreshTime(AfJobTime afJobTime) {
        if (afJobTime.getId() == null) {
            afJobTime.setId(idService.getDateSeq());
            afJobTimeMapper.insert(afJobTime);
            return;
        }
        afJobTimeMapper.updateById(afJobTime);
    }


    /**
     * 补偿异常的报告
     */
    @XxlJob("MakeupExceptionReportJob")
    public void makeupExceptionReport() {
        log.info("补偿异常的报告 任务开始了");
        int makeupSize = 0;
        final int pageSize = 1000;
        int page = 1;
        boolean loopCondition = true;
        try {
            do {

                List<AfReportRecord> reportRecords = afReportRecordMapper.getStartStateReportRecord(page, pageSize);
                if (reportRecords == null || reportRecords.size() < pageSize) {
                    // 结束循环
                    loopCondition = false;
                }
                if (reportRecords != null) {
                    updateReportRecordPatientId(reportRecords);
                    List<Long> taskIds = reportRecords.stream().map(AfReportRecord::getTaskId).collect(Collectors.toList());
                    reportService.makeupThreePartyPushReportByTaskIds(taskIds);
                }
                page++;
            } while (loopCondition);
        } catch (Exception ex) {
            log.error("补偿异常的报告出错啦！" + ex.getMessage(), ex);
        }
        log.info("补偿异常的报告 任务结束了,本次补偿报告 {} 条", makeupSize);
    }

    private void updateReportRecordPatientId(List<AfReportRecord> reportRecords) {
        if (reportRecords == null || reportRecords.isEmpty()) {
            return;
        }
        for (AfReportRecord reportRecord : reportRecords) {
            if (Func.isNotBlank(reportRecord.getPatientId())) {
                continue;
            }
            try {
                // 如果出现多条出错的情况，还是得保存收到的信息，人工干预处理
                String patientId = tBasicMapper.getPatientIdByInpatientNoAndAdminssTimes(reportRecord.getInpatientNo(), reportRecord.getAdmissTimes());
                if (Func.isNotBlank(patientId)) {
                    afReportRecordMapper.updateReportRecordPatientId(patientId, reportRecord.getTaskId());
                }
            } catch (Exception ex) {
                log.error("查询病案主键出错了", ex);
            }
        }
    }
}
