package com.docus.server.collect.report.view;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.docus.core.util.SpringUtils;
import com.docus.infrastructure.redis.service.IdService;
import com.docus.server.api.IHospitalApi;
import com.docus.server.archivefile.infrastructure.entity.AfViewCollectionLog;
import com.docus.server.archivefile.service.IAfViewCollectionLogService;
import com.docus.server.collect.IJobResult;
import com.docus.server.collect.web.common.BasicProperties;
import com.docus.server.collect.web.common.DocusProperties;
import com.docus.server.collect.web.common.dto.BasicQueryDto;
import com.docus.server.collect.web.common.dto.CollectionForJZHDto;
import com.docus.server.collect.web.common.dto.CollectionSaveDto;
import com.docus.server.collect.web.enums.ColectNameEnum;
import com.docus.server.collect.web.enums.DisposeModeEnum;
import com.docus.server.collect.web.enums.MedicalRecordEnum;
import com.docus.server.collect.web.enums.RedisKeyEnum;
import com.docus.server.collect.web.utils.MqQueueUtils;
import com.docus.server.collect.web.utils.RedisMq;
import com.docus.server.collect.web.utils.SpringRestTemplateUtils;
import com.docus.server.common.message.MqMessage;
import com.docus.server.record.service.ITBasicService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public abstract class AbstractViewJobResultImpl<T> implements IJobResult<T> {
    private IHospitalApi hospitalApi;
    @Resource
    private IdService idService;
    @Resource
    private AmqpTemplate amqpTemplate;
    @Resource
    private BasicProperties basicProperties;
    @Resource
    private DocusProperties docusProperties;
    @Resource
    private MqQueueUtils mqQueueUtils;
    @Resource
    private Environment environment;
    @Resource(name = "defRedis")
    private RedisMq redisMq;
    @Resource
    private IAfViewCollectionLogService afViewCollectionLogService;
    @Resource
    private ITBasicService basicService;

    private String jzhkey = "FVISIT_ID";
    private String syscodekey = "SYS_CODE";

    @Override
    @SuppressWarnings("unchecked")
    public void handle(T results, String dsKey) {
        this.hospitalApi = (IHospitalApi) SpringUtils.getBean(String.format("%s%s", dsKey, "ServiceImpl"));
        process((List<Map<String, Object>>) results, dsKey);
    }

    public void process(List<Map<String, Object>> datas, String key) {
        String mqKey = String.format("topic_task_%s_queue", key);
        MqMessage mqMessage = new MqMessage();
        //将key转为大写以免出错
        datas = toReplaceKeyUp(datas);
        // 去掉所有String值的前后空格
        toReplaceBlank(datas);
        boolean bflage = true;
        List<Map<String, Object>> list = new ArrayList<>();
        //包含报告时间并没有jzh数据处理
        if (datas.get(0).containsKey(ColectNameEnum.EXAMTIME.value())
            && ((!datas.get(0).containsKey(ColectNameEnum.JZH.value())) || StringUtils.isEmpty(datas.get(0).get(ColectNameEnum.JZH.value())))) {
            //根据住院号取得患者数据，根据报告时间属于哪个出入院时间之间，如无则按最近算
            list = BatchForEXAMTIME(datas);
        } else {
            //正常数据处理，根据jzh取得患者本次病案采集器全部文件
            list = BatchForJZH(datas);
        }
        list = GenerateSDPriority(list);
        if (list.size() > 0) {
            GenerateQueue(mqKey, mqMessage, list);
        }
        log.info("本次采集：" + datas.size() + "笔" + key);
        log.info("本次批采患者数据：" + list.size() + "笔" + key);
        log.debug("本次批采患者原始数据：" + JSON.toJSONString(datas));
        log.debug("本次批采患者数据：" + JSON.toJSONString(list));
        datas.clear();
        list.clear();
    }

    private void GenerateQueue(String mqKey, MqMessage mqMessage, List<Map<String, Object>> list) {
        log.info("队列生成方式：{},推送 {} 条数据", docusProperties.getMode(), list.size());
        if (docusProperties.getMode().equals(DisposeModeEnum.mq)) {
            mqQueueUtils.DeclareQueue(mqKey);
            mqMessage.setMessageBody(JSON.toJSONString(list, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue));
            amqpTemplate.convertAndSend("", mqKey, mqMessage);
        }
        if (docusProperties.getMode().equals(DisposeModeEnum.redis)) {
            redisMq.push(RedisKeyEnum.QUEUEREDISKEY, JSON.toJSONString(list, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue));
        }
    }

    /**
     * 任务优先级
     *
     * @param datas
     * @return
     */
    private List<Map<String, Object>> GenerateSDPriority(List<Map<String, Object>> datas) {
        if (!(!StringUtils.isEmpty(docusProperties.getPriority()) && docusProperties.getPriority().equals("1"))) {
            return datas;
        }
        int priority = 1;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String nowday = sdf.format(new Date());
        String oldDate = "";
        if (datas != null && datas.size() > 0) {
            if (datas.get(0).containsKey(ColectNameEnum.ModifyTime.value()) && !ObjectUtils.isEmpty(datas.get(0).get(ColectNameEnum.ModifyTime.value()))) {
                if (datas.get(0).get(ColectNameEnum.ModifyTime.value()) instanceof java.util.Date) {
                    java.util.Date t = (java.util.Date) datas.get(0).get(ColectNameEnum.ModifyTime.value());
                    oldDate = sdf.format(t);
                }
                if (datas.get(0).get(ColectNameEnum.ModifyTime.value()) instanceof java.sql.Date) {
                    java.sql.Date t = (java.sql.Date) datas.get(0).get(ColectNameEnum.ModifyTime.value());
                    oldDate = sdf.format(t);
                }
                if (datas.get(0).get(ColectNameEnum.ModifyTime.value()) instanceof String) {
                    oldDate = String.valueOf(datas.get(0).get(ColectNameEnum.ModifyTime.value())).replace("-", "").substring(0, 8);
                }
            }
            if (oldDate.substring(0, 6).equals("202208")) {
                priority = 2;
            }
            if (oldDate.equals(nowday)) {
                priority = 3;
            }
        }
        for (Map<String, Object> o : datas) {
            o.put(ColectNameEnum.priority.value(), priority);
        }

        return datas;
    }

    /**
     * 根据jzh取得所需采集的批量数据
     *
     * @param datas
     */
    private List<Map<String, Object>> BatchForJZH(List<Map<String, Object>> datas) {
        String oldJzhkey = "";
        String syscode = String.valueOf(datas.get(0).get(syscodekey));
        List<String> jzhs = datas.stream().map(t -> String.valueOf(t.get(jzhkey))).distinct().collect(Collectors.toList());
        BasicQueryDto dto = new BasicQueryDto();
        //没用
//        FieldJsonDto fieldJsonDto = dto.getFields().stream().filter(t -> t.getNewfield().equals(jzhkey)).findFirst().orElse(null);
//        if (fieldJsonDto != null) {
//            oldJzhkey = fieldJsonDto.getOldfield();
//        }

        if (datas.get(0).containsKey(ColectNameEnum.MedicalRecord.value())) {
            String MedicalRecord = String.valueOf(datas.get(0).get(ColectNameEnum.MedicalRecord.value()));
            if (MedicalRecord.equals(MedicalRecordEnum.jzhAndTimes.value())) {
                return GetColectionForJZHAndAdmissTimes(dto, oldJzhkey, syscode, jzhs, datas);
            }
            if (MedicalRecord.equals(MedicalRecordEnum.zyhAndTimes.value())) {
                jzhs = datas.stream().map(t -> String.valueOf(t.get(ColectNameEnum.ZYH.value())).trim() + "_" + String.valueOf(t.get(ColectNameEnum.AdmissTimes.value())).trim()).distinct().collect(Collectors.toList());
                return GetColectionForZYHAndAdmissTimes(dto, oldJzhkey, syscode, jzhs, datas);
            }
        }
        return GetColectionForJZH(dto, oldJzhkey, syscode, jzhs);
    }

    private List<Map<String, Object>> GetColectionForJZHAndAdmissTimes(BasicQueryDto dto, String oldJzhkey, String syscode, List<String> jzhs, List<Map<String, Object>> datas) {
        List<Map<String, Object>> batchcollects = hospitalApi.BatchForJZHAndAdmissTimes(datas);
        toReplaceBlank(batchcollects);
        return GetColectionForJZH(syscode, jzhs, batchcollects);
    }

    private List<Map<String, Object>> GetColectionForZYHAndAdmissTimes(BasicQueryDto dto, String oldJzhkey, String syscode, List<String> jzhs, List<Map<String, Object>> datas) {
        List<Map<String, Object>> batchcollects = hospitalApi.BatchForZYHAndAdmissTimes(datas);
        toReplaceBlank(batchcollects);
        return GetColectionForJZH(syscode, jzhs, batchcollects);
    }

    /**
     * 取得历史采集数据
     *
     * @param jzhs
     * @param syscode
     * @return
     */
    private List<AfViewCollectionLog> getOldConllectionLog(List<String> jzhs, String syscode) {
        CollectionForJZHDto jzhDto = new CollectionForJZHDto();
        jzhDto.setJzhs(jzhs);
        jzhDto.setSyscode(syscode);
        String url = String.format("http://localhost:%s", getPort());
        String requstParam = JSON.toJSONString(jzhDto);
        String sendPost = SpringRestTemplateUtils.getInstance().sendPost(url + "/api/conllection/logs", requstParam, MediaType.APPLICATION_JSON, null, true);
        ObjectMapper objectMapper = new ObjectMapper();
        List<AfViewCollectionLog> datas = new ArrayList<>();
        try {
            datas = objectMapper.readValue(sendPost, new TypeReference<List<AfViewCollectionLog>>() {
            });
        } catch (Exception ex) {
            log.error("解析失败：" + sendPost);
            return null;
        }
        return datas;
    }

    private List<Map<String, Object>> GetColectionForJZH(String syscode, List<String> jzhs, List<Map<String, Object>> batchcollects) {
        //转为大写
        batchcollects = toReplaceKeyUp(batchcollects);
        batchcollects = batchcollects.stream().distinct().collect(Collectors.toList());
        log.debug("JZH 处理后的数据 {} 条", batchcollects.size());
        Boolean recordlog = false;
        if (batchcollects != null && batchcollects.size() > 0) {
            if (batchcollects.get(0).containsKey(ColectNameEnum.RecordLog.value())) {
                recordlog = true;
            }
        }
        log.debug("recordlog:{}", recordlog);
//        LambdaQueryWrapper<AfViewCollectionLog> queryWrapper = Wrappers.lambdaQuery();
//        queryWrapper.in(AfViewCollectionLog::getJzh, jzhs).eq(AfViewCollectionLog::getSysCode, syscode);
        List<AfViewCollectionLog> oldcollects = afViewCollectionLogService.findByJzhAndSysCode(jzhs, syscode);
//        List<AfViewCollectionLog> oldcollects = getOldConllectionLog(jzhs, syscode);
        List<Map<String, Object>> newcollects = new ArrayList<>();
        List<AfViewCollectionLog> updates = new ArrayList<>();
        List<AfViewCollectionLog> adds = new ArrayList<>();
        for (Map<String, Object> o : batchcollects) {
            String fileid = String.valueOf(o.get(ColectNameEnum.FILEID.value())).trim();
            String jzhdata = String.valueOf(o.get(jzhkey));
            String MedicalRecord = String.valueOf(o.get(ColectNameEnum.MedicalRecord.value()));
            if (MedicalRecord.equals(MedicalRecordEnum.zyhAndTimes.value())) {
                jzhdata = String.valueOf(o.get(ColectNameEnum.ZYH.value())).trim() + "_" + String.valueOf(o.get(ColectNameEnum.AdmissTimes.value())).trim();
            }
            String jzh = jzhdata;
            String modifytime = String.valueOf(o.get(ColectNameEnum.ModifyTime.value()));
            AfViewCollectionLog collectionLog = oldcollects.stream().filter(t -> t.getFileId().equals(fileid) && t.getJzh().equals(jzh)).findFirst().orElse(null);
            log.debug("fileId {}  AfViewCollectionLog is null? {}", fileid, collectionLog == null);
            if (null == collectionLog) {
                //电子病历，记录是否更新，合并时只给已更新的
                if (recordlog) {
                    o.put(ColectNameEnum.nowdata.value(), 1);
                }
                newcollects.add(o);
                log.debug("collectionLog is null");
                AfViewCollectionLog logadd = new AfViewCollectionLog();
                logadd.setFileId(fileid);
                logadd.setCreateTime(new Date());
                logadd.setFileModifyTime(modifytime);
                logadd.setJzh(jzh);
                logadd.setSysCode(syscode);
                logadd.setId(idService.getDateSeq());
                adds.add(logadd);
                continue;
            }
            if (!collectionLog.getFileModifyTime().equals(modifytime)) {
                log.debug("collectionLog FileModifyTime is not eq view FileModifyTime");
                if (recordlog) {
                    o.put(ColectNameEnum.nowdata.value(), 1);
                }
                newcollects.add(o);
                collectionLog.setFileModifyTime(modifytime);
                updates.add(collectionLog);
                continue;
            }
            if (recordlog) {
                o.put(ColectNameEnum.nowdata.value(), 1);
                newcollects.add(o);
            }
        }

        afViewCollectionLogService.insertBatchAfViewCollectionLogs(adds);
        afViewCollectionLogService.insertBatchAfViewCollectionLogs(updates);

        return newcollects;
    }

    private void SaveConllectionLog(List<AfViewCollectionLog> adds, List<AfViewCollectionLog> updates) {

        CollectionSaveDto dto = new CollectionSaveDto();

        dto.setAdds(adds);
        dto.setUpdates(updates);
        String url = String.format("http://localhost:%s", getPort());
        String requstParam = JSON.toJSONString(dto);
        SpringRestTemplateUtils.getInstance().sendPost(url + "/api/conllection/SaveLogs", requstParam, MediaType.APPLICATION_JSON, null, true);
    }

    /**
     * 把map key改为大写
     *
     * @param maps
     * @return
     */
    private static List<Map<String, Object>> toReplaceKeyUp(List<Map<String, Object>> maps) {
        List<Map<String, Object>> data = new ArrayList<>();
        for (Map<String, Object> o : maps) {
            Map re_map = new HashMap();
            for (Map.Entry<String, Object> entry : o.entrySet()) {
                re_map.put(entry.getKey().trim().toUpperCase(), entry.getValue());
            }
            data.add(re_map);
        }

        return data;
    }

    /**
     * 替换掉map中的String值的前后空格
     *
     * @param datas 数据
     */
    private static void toReplaceBlank(List<Map<String, Object>> datas) {
        if (datas == null || datas.isEmpty()) {
            return;
        }
        for (Map<String, Object> data : datas) {
            Set<Map.Entry<String, Object>> entries = data.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                Object value = entry.getValue();
                if (value instanceof String) {
                    entry.setValue(String.valueOf(value).trim());
                }
            }
        }
    }

    private List<Map<String, Object>> BatchForEXAMTIME(List<Map<String, Object>> datas) {
        String oldJzhkey = "";
        String syscode = String.valueOf(datas.get(0).get(ColectNameEnum.COLLECTID.value()));
        List<String> zyhs = datas.stream().map(t -> String.valueOf(t.get(ColectNameEnum.ZYH.value()))).distinct().collect(Collectors.toList());
        List<Map<String, Object>> basics = getBasicForZYHs(zyhs);
        if (null == basics || basics.size() <= 0) {
            return new ArrayList<>();
        }
        List<Map<String, Object>> list = new ArrayList<>();
        for (Map<String, Object> o : datas) {

            List<Map<String, Object>> temps = basics.stream().filter(t -> String.valueOf(t.get(ColectNameEnum.InpatientNo.value())).equals(
                String.valueOf(o.get(ColectNameEnum.ZYH.value())))
            ).collect(Collectors.toList());

            if (null == temps || temps.size() <= 0) {
                continue;
            }
            String examTime = String.valueOf(o.get(ColectNameEnum.EXAMTIME.value()));
            //region 取得出入院区间是否有数据
            Map<String, Object> temp = temps.stream().filter(t ->
                {
                    String AdmissDate = String.valueOf(t.get(ColectNameEnum.AdmissDate.value()));
                    String DisDate = String.valueOf(t.get(ColectNameEnum.DisDate.value()));
                    if (examTime.compareTo(AdmissDate) >= 0 && examTime.compareTo(DisDate) <= 0) {
                        return true;
                    }
                    return false;
                }
            ).findFirst().orElse(null);
            if (temp != null) {
                o.put(ColectNameEnum.JZH.value(), temp.get("jzh"));
                o.put(ColectNameEnum.AdmissDate.value(), temp.get(ColectNameEnum.AdmissDate.value()));
                o.put(ColectNameEnum.DisDate.value(), temp.get(ColectNameEnum.DisDate.value()));
                list.add(o);
                continue;
            }
            //endregion
            //region 取得大于入院日期的第一笔
            temp = temps.stream().filter(t ->
                {
                    String AdmissDate = String.valueOf(t.get(ColectNameEnum.AdmissDate.value()));
                    String DisDate = String.valueOf(t.get(ColectNameEnum.DisDate.value()));
                    if (examTime.compareTo(AdmissDate) >= 0 && examTime.compareTo(DisDate) >= 0) {
                        return true;
                    }
                    return false;
                }
            ).sorted(Comparator.comparing(a -> String.valueOf(a.get(ColectNameEnum.AdmissDate.value())), Comparator.reverseOrder())).findFirst().orElse(null);
            if (temp != null) {
                o.put(ColectNameEnum.JZH.value(), temp.get("jzh"));
                o.put(ColectNameEnum.AdmissDate.value(), temp.get(ColectNameEnum.AdmissDate.value()));
                o.put(ColectNameEnum.DisDate.value(), examTime);
                list.add(o);
                continue;
            }
            //endregion
            //region 取得最近一笔住院的
            temp = temps.stream().sorted(Comparator.comparing(a -> String.valueOf(a.get(ColectNameEnum.AdmissDate.value())), Comparator.reverseOrder())).findFirst().orElse(null);
            if (temp != null) {
                o.put(ColectNameEnum.JZH.value(), temp.get("jzh"));
                o.put(ColectNameEnum.AdmissDate.value(), temp.get(ColectNameEnum.AdmissDate.value()));
                o.put(ColectNameEnum.DisDate.value(), temp.get(ColectNameEnum.DisDate.value()));
                list.add(o);
                continue;
            }
            //endregion

        }

        //取得该患者全部住院文件
        List<Map<String, Object>> batchcollects = hospitalApi.BatchForEXAMTIME(list);
        toReplaceBlank(batchcollects);
        //添加记帐号
        for (Map<String, Object> k : batchcollects) {
            Map<String, Object> temp = list.stream().filter(t -> String.valueOf(t.get(ColectNameEnum.ZYH.value())).equals(
                String.valueOf(k.get(ColectNameEnum.ZYH.value())))
            ).findFirst().orElse(null);
            k.put(ColectNameEnum.JZH.value(), temp.get(ColectNameEnum.JZH.value()));
        }
        list.forEach(t ->
            {
                t.remove(ColectNameEnum.AdmissDate.value());
                t.remove(ColectNameEnum.DisDate.value());
            }
        );
        batchcollects.removeAll(list);
        batchcollects.addAll(list);
        List<String> jzhs = list.stream().map(t -> String.valueOf(t.get(ColectNameEnum.JZH.value()))).collect(Collectors.toList());
        return GetColectionForJZH(syscode, jzhs, batchcollects);
    }

    private List<Map<String, Object>> GetColectionForJZH(BasicQueryDto dto, String oldJzhkey, String syscode, List<String> jzhs) {
        jzhs = jzhs.stream().distinct().collect(Collectors.toList());
        List<Map<String, Object>> batchcollects = hospitalApi.BatchForJZH(jzhs);
        log.debug("size:{}", batchcollects.size());
        toReplaceBlank(batchcollects);
        return GetColectionForJZH(syscode, jzhs, batchcollects);
    }

    /**
     * 根据住院号取得住院数据
     *
     * @param zyhs
     * @return
     */
    private List<Map<String, Object>> getBasicForZYHs(List<String> zyhs) {

        return basicService.getBasicForZYHs(zyhs);

//        List<Map<String, Object>> datas = new ArrayList<>();
//        String url = String.format("http://localhost:%s", getPort());
//        String requstParam = JSON.toJSONString(zyhs);
//        String sendPost = SpringRestTemplateUtils.getInstance().sendPost(url + "/api/conllection/getBasicForZYHs", requstParam, MediaType.APPLICATION_JSON, null, true);
//        ObjectMapper objectMapper = new ObjectMapper();
//        try {
//            datas = objectMapper.readValue(sendPost, new TypeReference<List<Map<String, Object>>>() {
//            });
//        } catch (Exception ex) {
//            log.error("解析失败：" + sendPost);
//            return null;
//        }
//
//        return datas;
    }

    /**
     * 取得本机端口
     *
     * @return
     */
    private String getPort() {
        return environment.getProperty("local.server.port");
    }

    @Override
    public T ok(Map<String, Object> params) {
        return null;
    }

    @Override
    public T fail(Map<String, Object> params) {
        return null;
    }

}
