package com.luca.pilot.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.luca.pilot.bizEnum.TableEnum;
import com.luca.pilot.entity.*;
import com.luca.pilot.service.PlanService;
import com.luca.pilot.util.CrfUtil;
import com.mongodb.bulk.BulkWriteResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class PlanServiceImpl implements PlanService {

    @Resource(name = "mongoTemplate")
    private MongoTemplate mongoTemplate;

    @Resource(name = "mongoArchiveTemplate")
    private MongoTemplate mongoArchiveTemplate;

    @Override
    @Scheduled(cron ="0 0/5 * * * ?")
    public void synchronizePlanTask() {
        log.info("--------------synchronizePlanTask start---------");
        LocalDateTime now = LocalDateTime.now();

        SynchronizeTime synchronizeTime = findSynchronizeTime();

        LocalDateTime lastSynchronizeTime = null;
        if (Objects.nonNull(synchronizeTime)) {
            lastSynchronizeTime = synchronizeTime.getPlan();
        }

        Query countQuery = new Query();
        if (Objects.nonNull(lastSynchronizeTime)) {
            countQuery.addCriteria(Criteria.where("last_modified_at").gt(String.valueOf(lastSynchronizeTime)));
        }
        long totalPlanTaskDetailsCount = mongoTemplate.count(countQuery, PlanTaskDetails.class);
        log.info("PlanTaskDetails 在大于 {} 时间内未查询到数据 {} 条", lastSynchronizeTime, totalPlanTaskDetailsCount);
        if (totalPlanTaskDetailsCount == 0) {
            return;
        }

        saveSynchronizeTime(synchronizeTime, now);

        long skip = totalPlanTaskDetailsCount / 10000;
        if (totalPlanTaskDetailsCount % 10000 > 0) {
            skip++;
        }

        long totalPlanModuleCount = mongoTemplate.count(countQuery, PlanModule.class);

        BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, PlanModule.class);

        for (int i = 0; i < skip; i++) {
            countQuery.skip(i * 10000L);
            countQuery.limit(10000);
            List<PlanTaskDetails> planTaskDetails = mongoTemplate.find(countQuery, PlanTaskDetails.class);
            log.info("第{}次查询 planTaskDetails count:{}", i + 1, planTaskDetails.size());
            // 获取对应档案,取subjectId 和 randomId
            List<UserArchiveMapping> userArchiveMappings = queryArchiveMapping(planTaskDetails);
            List<UserArchive> userArchives = queryArchive(userArchiveMappings);

            List<Project> projects = queryProjct(planTaskDetails);
            List<Site> sites = querySites(userArchiveMappings);

            List<PlanTask> planTasks = queryPlanTasks(planTaskDetails);
            List<Plan> plans = queryPlans(planTasks);
            List<PlanTaskModuleRelate> planMoudleRelates = queryPlanMoudleRelates(planTasks);
            List<PlanTaskDetailsModule> planTaskDetailsModules = queryPlanTaskDetaiMoudles(planTaskDetails);

            Map<Long, String> relationNameMap = queryRelateMoudleName(planMoudleRelates);

            Map<Long, Map<String, String>> resultMap = queryPlanTaskDetailResult(planTaskDetails);

            Map<Long, Map<Long, Long>> digitalMedicalEventMap = queryDigitalMedicalEvent(planTaskDetails);
            Map<Long, Map<Long, String>> digitalMedicalTypeMap = queryDigitalMedicalType(planTaskDetails);

            List<PlanModule> planMoudles = new ArrayList<>();


            //以 planTaskDetail 和 planMoudleRelate 为基准
            // 一个 planTaskDetail 能对应多个 planMoudleRelate,即一次任务配置了多少个模块(问卷,量表,数字靶点)
            for (PlanTaskDetails planTaskDetail : planTaskDetails) {
                UserArchiveMapping userArchiveMapping = userArchiveMappings.stream().filter(x -> x.getPatientCode().equals(planTaskDetail.getPatientCode())).findFirst().orElse(null);

                UserArchive userArchive = userArchives.stream().filter(x -> Objects.nonNull(userArchiveMapping) && x.getId().equals(userArchiveMapping.getUserArchiveId())).findFirst().orElse(null);

                Project project = projects.stream().filter(x -> x.getId().equals(planTaskDetail.getProjectId())).findFirst().orElse(null);

                Site site = sites.stream().filter(x -> Objects.nonNull(userArchiveMapping) && x.getId().equals(userArchiveMapping.getSiteId())).findFirst().orElse(null);

                PlanTask planTask = planTasks.stream().filter(x -> x.getId().equals(planTaskDetail.getPlanTaskId())).findFirst().orElse(null);

                Plan plan = plans.stream().filter(x -> Objects.nonNull(planTask) && x.getId().equals(planTask.getPlanId())).findFirst().orElse(null);

                List<PlanTaskModuleRelate> relates = planMoudleRelates.stream().filter(x -> Objects.nonNull(planTask) && x.getPlanTaskId().equals(planTask.getId())).collect(Collectors.toList());

                List<PlanTaskDetailsModule> modules = planTaskDetailsModules.stream().filter(x -> Objects.nonNull(planTaskDetail) && x.getPlanTaskDetailsId().equals(planTaskDetail.getId())).collect(Collectors.toList());

                for (PlanTaskModuleRelate relate : relates) {
                    PlanModule planMoudle = new PlanModule();

                    planMoudle.setKey(planTaskDetail.getId() + String.valueOf(relate.getId()));

                    if (Objects.nonNull(userArchive)) {
                        planMoudle.setSubjectId(userArchive.getSubjectId());
                        planMoudle.setRandomizationId(userArchive.getRandomizationId());
                    }

                    if (Objects.nonNull(project)) {

                        planMoudle.setProjectName(project.getName());
                    }
                    if (Objects.nonNull(site)) {
                        planMoudle.setSiteName(site.getSiteName());
                    }

                    if (Objects.nonNull(plan)) {
                        planMoudle.setPlanId(plan.getId());
                        planMoudle.setPlanCode(plan.getNumber());
                        planMoudle.setPlanEffectiveDate(parseTimeFromDate(plan.getEffectiveDate()));
                        planMoudle.setPlanDuration(plan.getDays());
                    }

                    if (Objects.nonNull(planTask)) {
                        planMoudle.setPlanTaskName(planTask.getName());
                        planMoudle.setPlanTaskdescription(planTask.getDescription());
                        planMoudle.setPlanTaskType(planTask.getTaskType());
                        planMoudle.setPlanTaskTaskCount(planTask.getTaskCount());
                        planMoudle.setPlanTaskFinishDay(planTask.getFinishDay());
                        planMoudle.setPlanTaskLoopType(planTask.getLoopType());
                        planMoudle.setPlanTaskEnabled(planTask.getEnabled());
                        planMoudle.setPlanTaskIsCirculation(planTask.getIsCirculation());
                        planMoudle.setPlanTaskBeginDay(planTask.getBeginDay());
                        planMoudle.setPlanTaskCirculationDay(planTask.getCirculationDay());
                        planMoudle.setPlanTaskWindowPhase(planTask.getWindowPhase());
                        planMoudle.setPlanTaskEndDay(planTask.getEndDay());
                    }

                    if (Objects.nonNull(planTaskDetail)) {
                        planMoudle.setProjectCode(String.valueOf(planTaskDetail.getProjectId()));
                        planMoudle.setTaskStartDate(planTaskDetail.getStartDate());
                        planMoudle.setTaskEndDate(planTaskDetail.getEndDate());
                        planMoudle.setTaskCompleteStatus(planTaskDetail.getCompleteStatus());
                        planMoudle.setTaskCompleteTime(planTaskDetail.getCompleteTime());
                        planMoudle.setTaskEnabled(planTaskDetail.getEnabled());
                        planMoudle.setTaskCompleteOrder(planTaskDetail.getCompleteOrder());
                    }

                    if (Objects.nonNull(relate)) {
                        planMoudle.setModuleType(relate.getRelationType());
                        planMoudle.setModuleId(relate.getRelationId());
                    }

                    if (MapUtil.isNotEmpty(relationNameMap) && Objects.nonNull(relationNameMap.get(relate.getRelationId()))) {
                        planMoudle.setModuleName(relationNameMap.get(relate.getRelationId()));
                    }

                    if (MapUtil.isNotEmpty(resultMap)) {
                        Map<String, String> planTaskDetailMap = resultMap.get(planTaskDetail.getId());

                        if (MapUtil.isNotEmpty(planTaskDetailMap)) {
                            String result = planTaskDetailMap.get(String.valueOf(relate.getRelationId()));
                            if (!StringUtils.isEmpty(result)) {
                                planMoudle.setResult(result);
                            }
                        }
                    }

                    if (relate.getRelationType().equals("DIGITAL_MEDICAL")) {
                        if (MapUtil.isNotEmpty(digitalMedicalEventMap)) {
                            Map<Long, Long> eventMap = digitalMedicalEventMap.get(planTaskDetail.getId());
                            if (MapUtil.isNotEmpty(eventMap)) {
                                Long eventId = eventMap.get(relate.getRelationId());
                                if (Objects.nonNull(eventId)) {
                                    planMoudle.setDigitalModuleEventId(eventId);
                                }
                            }
                        }
                        if (MapUtil.isNotEmpty(digitalMedicalTypeMap)) {
                            Map<Long, String> typeMap = digitalMedicalTypeMap.get(planTaskDetail.getId());
                            if (MapUtil.isNotEmpty(typeMap)) {
                                String eventType = typeMap.get(relate.getRelationId());
                                if (Objects.nonNull(eventType)) {
                                    String tableName = TableEnum.getTableNameByType(eventType);
                                    if (Objects.nonNull(tableName)) {
                                        planMoudle.setDigitalModuleTableName(tableName);
                                    }
                                }
                            }
                        }
                    }

                    PlanTaskDetailsModule module = modules.stream().filter(x -> x.getRelationId().equals(relate.getRelationId())).findFirst().orElse(null);
                    if (Objects.nonNull(module)) {
                        planMoudle.setModuleComplete(module.getModuleComplete());
                        planMoudle.setModuleIgnoreRemark(module.getIgnoreRemark());
                        if (Objects.nonNull(module.getModuleComplete()) && module.getModuleComplete().equals(1)) {
                            planMoudle.setModuleFinishTime(module.getLastModifiedAt());
                        }
                    } else {
                        planMoudle.setModuleComplete(0);
                    }

                    // 是否第一次全量插入
                    if (totalPlanModuleCount > 0) {
                        Query upsertQuery = new Query(Criteria.where("key").is(planMoudle.getKey()));
                        Update update = buildUpdate(planMoudle);
                        bulkOps.upsert(upsertQuery, update);
                    }
                    planMoudles.add(planMoudle);
                }
            }

            log.info("planMoudles size:{}", planMoudles.size());

            // 是否第一次全量插入
            if (totalPlanModuleCount > 0) {
                BulkWriteResult execute = bulkOps.execute();
                log.info("BulkWriteResult:{} ", JSONUtil.toJsonStr(execute));
            } else {
                if (!CollectionUtils.isEmpty(planMoudles)) {
                    mongoTemplate.insert(planMoudles, PlanModule.class);
                }
            }

        }

        log.info("synchronizePlanTask end, 耗时:{} 秒", LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - now.toEpochSecond(ZoneOffset.of("+8")));

    }

    private SynchronizeTime findSynchronizeTime() {
        Query query = new Query().limit(1);
        return mongoTemplate.findOne(query, SynchronizeTime.class);
    }

    private void saveSynchronizeTime(SynchronizeTime synchronizeTime, LocalDateTime now) {
        if (Objects.isNull(synchronizeTime)) {
            SynchronizeTime time = new SynchronizeTime();
            time.setPlan(now);
            mongoTemplate.save(time);
        } else {
            Query updateQuery = new Query();
            updateQuery.addCriteria(Criteria.where("_id").is(synchronizeTime.get_id()));
            Update update = new Update();
            update.set("plan", now);
            mongoTemplate.updateFirst(updateQuery, update, SynchronizeTime.class);
        }
    }

    private Update buildUpdate(PlanModule planMoudle) {
        return new Update()
                .set("key", planMoudle.getKey())
                .set("subjectId", planMoudle.getSubjectId())
                .set("randomizationId", planMoudle.getRandomizationId())
                .set("projectCode", planMoudle.getProjectCode())
                .set("projectName", planMoudle.getProjectName())
                .set("siteName", planMoudle.getSiteName())
                .set("planId", planMoudle.getPlanId())
                .set("planCode", planMoudle.getPlanCode())
                .set("planDuration", planMoudle.getPlanDuration())
                .set("planTaskName", planMoudle.getPlanTaskName())
                .set("planTaskdescription", planMoudle.getPlanTaskdescription())
                .set("planTaskType", planMoudle.getPlanTaskType())
                .set("planTaskTaskCount", planMoudle.getPlanTaskTaskCount())
                .set("planTaskFinishDay", planMoudle.getPlanTaskFinishDay())
                .set("planTaskLoopType", planMoudle.getPlanTaskLoopType())
                .set("planTaskEnabled", planMoudle.getPlanTaskEnabled())
                .set("planTaskIsCirculation", planMoudle.getPlanTaskIsCirculation())
                .set("planTaskBeginDay", planMoudle.getPlanTaskBeginDay())
                .set("planTaskCirculationDay", planMoudle.getPlanTaskCirculationDay())
                .set("planTaskWindowPhase", planMoudle.getPlanTaskWindowPhase())
                .set("planTaskEndDay", planMoudle.getPlanTaskEndDay())
                .set("taskStartDate", planMoudle.getTaskStartDate())
                .set("taskEndDate", planMoudle.getTaskEndDate())
                .set("taskCompleteStatus", planMoudle.getTaskCompleteStatus())
                .set("taskCompleteTime", planMoudle.getTaskCompleteTime())
                .set("taskEnabled", planMoudle.getTaskEndDate())
                .set("taskCompleteOrder", planMoudle.getTaskCompleteOrder())
                .set("moduleType", planMoudle.getModuleType())
                .set("moduleId", planMoudle.getModuleId())
                .set("moduleName", planMoudle.getModuleName())
                .set("moduleComplete", planMoudle.getModuleComplete())
                .set("moduleIgnoreRemark", planMoudle.getModuleIgnoreRemark())
                .set("moduleFinishTime", planMoudle.getModuleFinishTime())
                .set("result", planMoudle.getResult())
                .set("digitalModuleTableName", planMoudle.getDigitalModuleTableName())
                .set("digitalModuleEventId", planMoudle.getDigitalModuleEventId())
                .set("planEffectiveDate", planMoudle.getPlanEffectiveDate());
    }

    @Override
    public void test() {

    }


    private String parseTimeFromDate(LocalDate timeStr) {
        LocalDateTime localDateTime = timeStr.atStartOfDay();
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return localDateTime.format(fmt);
    }

    private List<PlanTaskDetailsModule> queryPlanTaskDetaiMoudles(List<PlanTaskDetails> planTaskDetails) {

        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(planTskDetailIds)) {
            return new ArrayList<>();
        }
        return mongoTemplate.find(new Query().addCriteria(Criteria.where("plan_task_details_id").in(planTskDetailIds)), PlanTaskDetailsModule.class);

    }

    private Map<Long, Map<Long, String>> queryDigitalMedicalType(List<PlanTaskDetails> planTaskDetails) {
        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(planTskDetailIds)) {
            return new HashMap<>();
        }

        Map<Long, List<ClinicalTrialsEvent>> eventMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("plan_details_id").in(planTskDetailIds).and("relation_type").is("DIGITAL_MEDICAL")), ClinicalTrialsEvent.class)
                .stream().collect(Collectors.groupingBy(ClinicalTrialsEvent::getPlanDetailsId));

        Map<Long, Map<Long, String>> map = new HashMap<>();
        eventMap.forEach((k, v) -> {
            Map<Long, String> innerMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(v)) {
                v.forEach(event -> {
                    innerMap.put(event.getRelationId(), event.getModuleItemType());
                });
                map.put(k, innerMap);
            }
        });

        return map;
    }

    private Map<Long, Map<Long, Long>> queryDigitalMedicalEvent(List<PlanTaskDetails> planTaskDetails) {
        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(planTskDetailIds)) {
            return new HashMap<>();
        }

        Map<Long, List<ClinicalTrialsEvent>> eventMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("plan_details_id").in(planTskDetailIds).and("relation_type").is("DIGITAL_MEDICAL")), ClinicalTrialsEvent.class)
                .stream().collect(Collectors.groupingBy(ClinicalTrialsEvent::getPlanDetailsId));

        Map<Long, Map<Long, Long>> map = new HashMap<>();
        eventMap.forEach((k, v) -> {
            Map<Long, Long> innerMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(v)) {
                v.forEach(event -> {
                    innerMap.put(event.getRelationId(), event.getEventId());
                });
                map.put(k, innerMap);
            }
        });

        return map;
    }

    private Map<Long, Map<String, String>> queryPlanTaskDetailResult(List<PlanTaskDetails> planTaskDetails) {
        Map<Long, Map<String, String>> map = new HashMap<>();
        Map<Long, Map<String, String>> scaleMap = queryScaleResult(planTaskDetails);
        map.putAll(scaleMap);
        Map<Long, Map<String, String>> questonaireMap = queryQuestionaireResult(planTaskDetails);

        questonaireMap.forEach((k, v) -> {
            if (map.containsKey(k)) {
                map.get(k).putAll(v);
            } else {
                map.put(k, v);
            }
        });

        Map<Long, Map<String, String>> crfMap = queryCrfResult(planTaskDetails);
        crfMap.forEach((k, v) -> {
            if (map.containsKey(k)) {
                map.get(k).putAll(v);
            } else {
                map.put(k, v);
            }
        });

        return map;
    }

    private Map<Long, Map<String, String>> queryCrfResult(List<PlanTaskDetails> planTaskDetails) {
        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(planTskDetailIds)) {
            return new HashMap<>();
        }

        List<CrfAnswer> crfAnswers = mongoTemplate.find(new Query().addCriteria(Criteria.where("plan_task_details_id").in(planTskDetailIds)), CrfAnswer.class);

        Map<Long, List<CrfAnswer>> crfAnswersMap = crfAnswers.stream().collect(Collectors.groupingBy(CrfAnswer::getPlanTaskDetailsId));

        Set<Long> crfIds = crfAnswers.stream().map(CrfAnswer::getCrfId).collect(Collectors.toSet());
        Map<Long, String> crfMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(crfIds)), Crf.class)
                .stream().collect(Collectors.toMap(Crf::getId, Crf::getQuestionJson, (k1, k2) -> k2));

        Map<Long, Map<String, String>> map = new HashMap<>();
        crfAnswersMap.forEach((k, v) -> {
            if (!CollectionUtils.isEmpty(v)) {
                Map<String, String> innerMap = new HashMap<>();
                v.forEach(crfAnswer -> {
                    String questionJson = crfMap.get(crfAnswer.getCrfId());
                    if (Objects.nonNull(questionJson) && Objects.nonNull(crfAnswer.getAnswerJson())) {
                        try {
                            String result = CrfUtil.parseCrfProblemAndAnswer(questionJson, crfAnswer.getAnswerJson());
                            if (Objects.nonNull(result)) {
                                innerMap.put(crfAnswer.getCrfTopId().toString(), result);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();

                        }
                    }
                });
                map.put(k, innerMap);
            }
        });

        return map;
    }

    private Map<Long, Map<String, String>> queryQuestionaireResult(List<PlanTaskDetails> planTaskDetails) {
        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(planTskDetailIds)) {
            return new HashMap<>();
        }

        List<QuestionnaireAnswerRecord> records = mongoTemplate.find(new Query().addCriteria(Criteria.where("plan_task_details_id").in(planTskDetailIds)), QuestionnaireAnswerRecord.class);

        if (CollectionUtils.isEmpty(records)) {
            return new HashMap<>();
        }

        Set<Long> recordIds = records.stream().map(QuestionnaireAnswerRecord::getId).collect(Collectors.toSet());
        List<QuestionnaireAnswer> answers = mongoTemplate.find(new Query().addCriteria(Criteria.where("record_id").in(recordIds)), QuestionnaireAnswer.class);

        Set<Long> ansowerIds = answers.stream().map(QuestionnaireAnswer::getId).collect(Collectors.toSet());
        List<QuestionnaireAnswerOption> answerOptions = mongoTemplate.find(new Query().addCriteria(Criteria.where("answer_id").in(ansowerIds)), QuestionnaireAnswerOption.class);

        Map<Long, Map<String, String>> map = new HashMap<>();

        for (QuestionnaireAnswerRecord record : records) {

            List<QuestionnaireAnswer> answerList = answers.stream().filter(x -> x.getRecordId().equals(record.getId())).collect(Collectors.toList());

            Map<String, String> resultMap = new HashMap<>();
            List<String> keyValueNewVos = new ArrayList<>();
            for (QuestionnaireAnswer answer : answerList) {
                Stream<QuestionnaireAnswerOption> questionnaireAnswerOptionStream = answerOptions.stream().filter(x -> x.getAnswerId().equals(answer.getId()) && x.getQuestionId().equals(answer.getQuestionId()));
                Optional<QuestionnaireAnswerOption> optionalAnswerOption = questionnaireAnswerOptionStream.findAny();

                switch (answer.getType()) {
                    case "CHOICE":
                        keyValueNewVos.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(QuestionnaireAnswerOption::getOptionName).orElse("-"));
                        break;
                    case "SLIDE":
                    case "DATE_SELECT":
                    case "NUMBER":
                        keyValueNewVos.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(option -> String.valueOf(option.getNumberAnswer())).orElse("-"));
                        break;
                    case "MULTIPLE_CHOICE":
                        List<String> optionNames = answerOptions.stream()
                                .filter(x -> x.getAnswerId().equals(answer.getId()) && x.getQuestionId().equals(answer.getQuestionId()))
                                .map(QuestionnaireAnswerOption::getOptionName)
                                .collect(Collectors.toList());
                        keyValueNewVos.add(answer.getQuestionName() + ":" + (optionNames.isEmpty() ? "-" : String.join(",", optionNames)));
                        break;
                    case "DATE":
                        keyValueNewVos.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(QuestionnaireAnswerOption::getDateAt).orElse("-"));
                        break;

                    case "SECTION_NUMBER":
                        keyValueNewVos.add(answer.getQuestionName() + ":" + (optionalAnswerOption.map(option -> option.getLeftMin() + "-" + option.getRightMax()).orElse("-")));
                        break;
                    case "TEXT":
                        keyValueNewVos.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(QuestionnaireAnswerOption::getContent).orElse("-"));
                        break;
                }
            }
            resultMap.put(String.valueOf(record.getTopId()), JSONUtil.toJsonStr(keyValueNewVos));
            map.put(record.getPlanTaskDetailsId(), resultMap);
        }

        return map;
    }

    private Map<Long, Map<String, String>> queryScaleResult(List<PlanTaskDetails> planTaskDetails) {
        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(planTskDetailIds)) {
            return new HashMap<>();
        }

        Map<Long, List<PatientScaleEvaluatingEntity>> scaleEvaluatMap =
                mongoTemplate.find(new Query().addCriteria(Criteria.where("plan_task_details_id").in(planTskDetailIds)), PatientScaleEvaluatingEntity.class)
                        .stream().collect(Collectors.groupingBy(PatientScaleEvaluatingEntity::getPlanTaskDetailsId));

        Map<Long, Map<String, String>> map = new HashMap<>();

        scaleEvaluatMap.forEach((k, v) -> {
            if (!CollectionUtils.isEmpty(v)) {
                Map<String, String> result = new HashMap<>();
                v.forEach(item -> {
                    List<String> sb = new ArrayList<>();
                    if (Objects.nonNull(item.getScaleResult())) {
                        sb.add("result:" + item.getScaleResult());
                    }
                    if (Objects.nonNull(item.getTotalScore())) {
                        sb.add("totalScore:" + item.getTotalScore());
                    }
                    if (!CollectionUtils.isEmpty(sb)) {
                        result.put(item.getScaleCode(), JSONUtil.toJsonStr(sb));
                    }

                });

                map.put(k, result);
            }
        });

        return map;
    }

    private Map<Long, String> queryRelateMoudleName(List<PlanTaskModuleRelate> planMoudleRelates) {
        /**
         * QUESTIONNAIRE 1
         * SCALE 1
         * DIGITAL_MEDICAL
         * CRF 1
         * COLLECT_FLOW
         *
         * INTELLIGENT_DEVICE
         * EXERCISE_MODULE
         *
         * E_DIARY
         */
        Map<Long, String> map = new HashMap<>();
        List<Long> questionnaireIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("QUESTIONNAIRE")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
        Map<Long, String> questionaireMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("top_id").in(questionnaireIds)), Questionnaire.class)
                .stream().collect(Collectors.toMap(Questionnaire::getTopId, Questionnaire::getName, (k1, k2) -> k2));
        if (MapUtil.isNotEmpty(questionaireMap)) {
            map.putAll(questionaireMap);
        }

        List<Long> crfTopIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("CRF")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
        Map<Long, String> crfMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("crf_top_id").in(crfTopIds)), Crf.class)
                .stream().collect(Collectors.toMap(Crf::getCrfTopId, Crf::getName, (k1, k2) -> k2));
        if (MapUtil.isNotEmpty(crfMap)) {
            map.putAll(crfMap);
        }

        List<Long> scaleIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("SCALE")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
        Map<Long, String> scaleMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(scaleIds)), ScaleModuleDetailsEntity.class)
                .stream().collect(Collectors.toMap(ScaleModuleDetailsEntity::getId, ScaleModuleDetailsEntity::getName, (k1, k2) -> k2));
        if (MapUtil.isNotEmpty(scaleMap)) {
            map.putAll(scaleMap);
        }

        List<Long> digitalMedicalIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("DIGITAL_MEDICAL")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
        Map<Long, String> digitalMedicalMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(digitalMedicalIds)), DigitalMedicalDetails.class)
                .stream().collect(Collectors.toMap(DigitalMedicalDetails::getId, DigitalMedicalDetails::getName, (k1, k2) -> k2));
        if (MapUtil.isNotEmpty(digitalMedicalMap)) {
            map.putAll(digitalMedicalMap);
        }

        List<Long> collectMoudleIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("COLLECT_FLOW")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
        Map<Long, String> collectMoudleMap = mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(collectMoudleIds)), CollectModule.class)
                .stream().collect(Collectors.toMap(CollectModule::getId, CollectModule::getName, (k1, k2) -> k2));
        if (MapUtil.isNotEmpty(collectMoudleMap)) {
            map.putAll(collectMoudleMap);
        }

        return map;
    }

    private List<UserArchiveMapping> queryArchiveMapping(List<PlanTaskDetails> planTaskDetails) {
        List<String> patientCodes = planTaskDetails.stream().map(PlanTaskDetails::getPatientCode).collect(Collectors.toList());
        Query archiveMappingquery = new Query();
        archiveMappingquery.addCriteria(Criteria.where("patient_code").in(patientCodes));
        return mongoTemplate.find(archiveMappingquery, UserArchiveMapping.class);
    }

    private List<PlanTaskModuleRelate> queryPlanMoudleRelates(List<PlanTask> planTasks) {
        List<Long> planTaskIds = planTasks.stream().map(PlanTask::getId).collect(Collectors.toList());
        return mongoTemplate.find(new Query().addCriteria(Criteria.where("planTaskId").in(planTaskIds)), PlanTaskModuleRelate.class);
    }

    private List<Site> querySites(List<UserArchiveMapping> userArchiveMappings) {
        List<Long> siteIds = userArchiveMappings.stream().map(UserArchiveMapping::getSiteId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(siteIds)) {
            return new ArrayList<>();
        }
        return mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(siteIds)),
                Site.class);
    }

    private List<Project> queryProjct(List<PlanTaskDetails> planTaskDetails) {
        List<Long> projectIds = planTaskDetails.stream().map(PlanTaskDetails::getProjectId).collect(Collectors.toList());
        return mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(projectIds)), Project.class);
    }

    private List<Plan> queryPlans(List<PlanTask> planTasks) {
        List<Long> planIds = planTasks.stream().map(PlanTask::getPlanId).collect(Collectors.toList());
        return mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(planIds)),
                Plan.class);
    }

    private List<PlanTask> queryPlanTasks(List<PlanTaskDetails> planTaskDetails) {
        List<Long> planTaskIds = planTaskDetails.stream().map(PlanTaskDetails::getPlanTaskId).collect(Collectors.toList());
        return mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(planTaskIds)),
                PlanTask.class);
    }

    private List<UserArchive> queryArchive(List<UserArchiveMapping> userArchiveMappings) {
        List<String> archiveIds = userArchiveMappings
                .stream().map(UserArchiveMapping::getUserArchiveId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(archiveIds)) {
            return new ArrayList<>();
        }
        return mongoArchiveTemplate.find(new Query().addCriteria(Criteria.where("_id").in(archiveIds)),
                UserArchive.class);
    }
}