package com.lantone.qc.kernel.catalogue.threelevelward;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lantone.qc.kernel.catalogue.QCCatalogue;
import com.lantone.qc.kernel.util.CatalogueUtil;
import com.lantone.qc.kernel.util.SimilarityUtil;
import com.lantone.qc.pub.model.InputInfo;
import com.lantone.qc.pub.model.OutputInfo;
import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
import com.lantone.qc.pub.model.doc.operation.OperationDiscussionDoc;
import com.lantone.qc.pub.model.doc.operation.OperationDoc;
import com.lantone.qc.pub.model.entity.Drug;
import com.lantone.qc.pub.model.label.LeaveHospitalLabel;
import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
import com.lantone.qc.pub.util.DateUtil;
import com.lantone.qc.pub.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author HUJING
 * @create 2020-08-18 19:13
 * @desc 减用抗生素未记录
 **/
@Component
public class THR03075 extends QCCatalogue {
    @Autowired
    SimilarityUtil similarityUtil;

    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
        status.set("0");
        List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
        if (doctorAdviceDocs.size() == 0) {
            return;
        }
        //抗生素及开医嘱时间(包括减用过抗生素的时间)     key:抗生素名    "2020-08-20,2020-08-21 ..."
        Map<String, List<String>> antibioticDate = Maps.newHashMap();
        //抗生素减用集合   key:抗生素名    value:  0:未减用,1及以上:减用次数
        Map<String, Integer> antibioticStatus = Maps.newHashMap();
        //抗生素及各初始剂量     key:抗生素名    value:抗生素第一次使用时剂量
        Map<String, List<Double>> antibioticValue = Maps.newHashMap();

        List<Map<String, String>> docAdvStruct = doctorAdviceDocs
                .stream()
                .filter(Objects::nonNull)
                .map(DoctorAdviceDoc::getStructureMap)
                .filter(x -> StringUtil.isNotBlank(x.get("药品类型")) && x.get("药品类型").contains("抗生素") && StringUtil.isNotBlank(x.get("医嘱单次剂量")))
                .filter(x -> StringUtil.isNotBlank(x.get("医嘱状态判别")) && !x.get("医嘱状态判别").contains("已停止"))
                .collect(Collectors.toList());

        String drugName = null, value = null, startDateStr = null;
        for (Map<String, String> structMap : docAdvStruct) {
            drugName = structMap.get("医嘱项目名称");
            value = structMap.get("医嘱单次剂量");
            startDateStr = structMap.get("医嘱开始时间");
            drugName = removeBracket(drugName);
            collectAntibioticInfo(antibioticDate, antibioticStatus, antibioticValue, drugName, value, startDateStr);
        }

        //把抗生素没减用过的抗生素删除
        for (Map.Entry<String, Integer> as : antibioticStatus.entrySet()) {
            if (as.getValue() == 0) {
                antibioticDate.remove(as.getKey());
                antibioticValue.remove(as.getKey());
            }
        }
        //抗生素减用过的集合如果为空，则一个抗生素都没有减用过，直接返回0
        if (antibioticDate.size() == 0) {
            return;
        }

        //病程记录中抗生素及查房时间(包括减用过抗生素的时间)     key:抗生素名    "2020-08-20,2020-08-21 ..."
        Map<String, List<String>> antibioticDateCourse = Maps.newHashMap();
        //病程记录中抗生素减用集合   key:抗生素名    value:  0:未减用,1及以上:减用次数
        Map<String, Integer> antibioticStatusCourse = Maps.newHashMap();
        //病程记录中抗生素及各初始剂量     key:抗生素名    value:抗生素第一次使用时剂量
        Map<String, List<Double>> antibioticValueCourse = Maps.newHashMap();
        String dateStr = null;
        /*********************************************查房记录********************************************************/
        if (threeLevelWardDocs.size() > 0) {
            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
            for (ThreeLevelWardDoc doc : allDoctorWradDocs) {
                if (doc.getThreeLevelWardLabel().size() == 0) {
                    continue;
                }
                dateStr = doc.getStructureMap().get("查房日期");
                ThreeLevelWardLabel label = doc.getThreeLevelWardLabel().get(0);
                List<Drug> drugs = label.getDrugs();
                getCourseDrugInfo(antibioticDateCourse, antibioticStatusCourse, antibioticValueCourse, dateStr, drugs);
            }
        }
        /*********************************************术后首程********************************************************/
        if (operationDocs.size() > 0) {
            List<OperationDiscussionDoc> operationDiscussionDocs = operationDocs
                    .stream()
                    .map(OperationDoc::getOperationDiscussionDoc)
                    .filter(Objects::nonNull)
                    .filter(x -> x.getOperationDiscussionLabel() != null)
                    .collect(Collectors.toList());
            for (OperationDiscussionDoc discussionDoc : operationDiscussionDocs) {
                dateStr = discussionDoc.getStructureMap().get("记录日期");
                if (StringUtil.isBlank(dateStr)) {
                    continue;
                }
                List<Drug> drugs = discussionDoc.getOperationDiscussionLabel().getDrugs();
                getCourseDrugInfo(antibioticDateCourse, antibioticStatusCourse, antibioticValueCourse, dateStr, drugs);
            }
        }
        /*********************************************出院小结********************************************************/
        if (leaveHospitalDoc != null) {
            LeaveHospitalLabel leaveHospitalLabel = leaveHospitalDoc.getLeaveHospitalLabel();
            dateStr = leaveHospitalDoc.getStructureMap().get("出院时间");
            if (leaveHospitalLabel != null && StringUtil.isNotBlank(dateStr)) {
                List<Drug> drugs = leaveHospitalLabel.getDrugs();
                getCourseDrugInfo(antibioticDateCourse, antibioticStatusCourse, antibioticValueCourse, dateStr, drugs);
            }
        }
        //将病程日期排序
        antibioticDateCourse.forEach((x, y) -> y.sort(Comparator.naturalOrder()));

        /**
         * 1.antibioticDate：从医嘱中取   key：抗生素名    value：医嘱中该抗生素所有减用时的时间（包括初始使用时间）
         * 2.antibioticDateWard：从查房记录中取     key：抗生素名    value：查房记录中该抗生素所有减用时的查房时间（包括初始使用时间）
         * 3.医嘱中该抗生素初始使用时间往后两天内，查房记录中该抗生素初始使用时间也在这两天内，则满足一半。
         * 4.医嘱中该抗生素减用时的时间往后两天内，查房记录中该抗生素减用时间也在这两天内，则满足条件，该抗生素通过该条规则
         * 5.继续判断下一个抗生素
         * 6.若医嘱中减用过的抗生素，查房记录中没出现过，则该抗生素会报出来（存入miss，规则最后会把所有不符合的抗生素都报出来）
         */
        StringBuffer sb = new StringBuffer();
        String drugKey = null, start = null, change = null, wardStartStr = null, wardChangeStr = null;
        List<String> dateList = null;
        for (Map.Entry<String, List<String>> ad : antibioticDate.entrySet()) {
            drugKey = ad.getKey();
            List<Double> antibioticValueList = antibioticValue.get(drugKey);//医嘱中该药品对应的所有用量
            String drugStandardWord = similarityUtil.getDrugStandardWord(drugKey);
            if (StringUtil.isNotBlank(drugStandardWord)) {
                drugKey = drugStandardWord;
            }
            /*if (!antibioticDateCourse.containsKey(drugKey)) {
                for (String date : ad.getValue()) {
                    infoAppend(sb, drugKey, date);
                }
                continue;
            }*/
            if (antibioticDateCourse.containsKey(drugKey)) {
                List<Double> antibioticValueWardList = antibioticValueCourse.get(drugKey);//病程记录中该药品对应的所有用量
                int findNum = 0;
                for (int i = 1; i < antibioticValueList.size(); i++) {//从加用的值开始，如果加用过的值查房记录中都有，则不报该药
                    if (antibioticValueWardList.contains(antibioticValueList.get(i))) {
                        findNum++;
                    }
                }
                if (findNum == antibioticValueList.size() - 1) {
                    continue;
                }
                dateList = ad.getValue();
                int matchNum = 0;
                List<String> wardDateStr = antibioticDateCourse.get(drugKey);
                for (int i = 0; i < dateList.size() - 1; i++) {
                    start = dateList.get(i);        //抗生素开医嘱时间
                    change = dateList.get(i + 1);   //抗生素用量改变时间
                    Date adStart = StringUtil.parseDateTime(start);
                    Date adChange = StringUtil.parseDateTime(change);
                    for (int j = 0; j < wardDateStr.size() - 1; j++) {
                        wardStartStr = wardDateStr.get(j);         //查房记录开抗生素时间
                        wardChangeStr = wardDateStr.get(j + 1);    //查房记录改变抗生素用量时间
                        Date wardStart = StringUtil.parseDateTime(wardStartStr);
                        Date wardChange = StringUtil.parseDateTime(wardChangeStr);
                        if (!CatalogueUtil.compareTime(adStart, wardStart, 48 * 60L) && !CatalogueUtil.compareTime(adChange, wardChange, 48 * 60L)) {
                            matchNum++;
                        }
                    }
                }
                if (dateList.size() - 1 != matchNum) {
                    infoAppend(sb, drugKey, change);
                }
            }
        }

        if (sb.toString().length() > 0) {
            status.set("-1");
            info.set(sb.toString().substring(0, sb.toString().length() - 1));
        }
    }

    /**
     * 收集各模块药品信息
     *
     * @param antibioticDateWard   病程中抗生素使用所有时间
     * @param antibioticStatusWard 病程中抗生素用量改变状态
     * @param antibioticValueWard  病程中抗生素及用量
     * @param dateStr              记录日期
     * @param drugs                模型提取出的药品列表
     */
    private void getCourseDrugInfo
    (Map<String, List<String>> antibioticDateWard, Map<String, Integer> antibioticStatusWard,
     Map<String, List<Double>> antibioticValueWard, String dateStr, List<Drug> drugs) {
        for (Drug drug : drugs) {
            String wardDrug = drug.getName();
            wardDrug = removeBracket(wardDrug);
            String drugStandardWord = similarityUtil.getDrugStandardWord(wardDrug);
            if (StringUtil.isNotBlank(drugStandardWord)) {
                wardDrug = drugStandardWord;
            }
            if (drug.getConsumption() != null) {
                String consumption = drug.getConsumption().getName();
                collectAntibioticInfo(antibioticDateWard, antibioticStatusWard, antibioticValueWard, wardDrug, consumption, dateStr);
            }
        }
    }

    /**
     * 收集抗生素各种信息
     *
     * @param antibioticDate   抗生素使用所有时间
     * @param antibioticStatus 抗生素用量改变状态
     * @param antibioticValue  抗生素及用量
     * @param drugName         抗生素名称
     * @param value            抗生素用量
     * @param startDateStr     抗生素使用时间（医嘱开始时间或查房时间）
     */
    private void collectAntibioticInfo
    (Map<String, List<String>> antibioticDate, Map<String, Integer> antibioticStatus,
     Map<String, List<Double>> antibioticValue, String drugName, String value, String startDateStr) {
        double v = -1;
        try {
            v = Double.parseDouble(getNumber(value));
        } catch (Exception e) {
            System.out.println("THR03075:       " + drugName + ":" + value + "解析异常");
        }
        if (v < 0) {
            return;
        }
        if (v > 100) {
            v = v / 1000;
        }
        if (!antibioticValue.containsKey(drugName)) {
            antibioticValue.put(drugName, Lists.newArrayList(v));
            antibioticDate.put(drugName, Lists.newArrayList(startDateStr));
            antibioticStatus.put(drugName, 0);
        } else {
            List<Double> beforeValue = antibioticValue.get(drugName);
            if (beforeValue.get(beforeValue.size() - 1) > v) {
                beforeValue.add(v);
                antibioticValue.put(drugName, beforeValue);//添减该抗生素更小的值
                antibioticStatus.put(drugName, antibioticStatus.get(drugName) + 1);
                antibioticDate.get(drugName).add(startDateStr);
            }
        }
    }

    public static String getNumber(String content) {
        String group = "";
        String compile = "([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9]|\\.\\d*[1-9]|0)";
        Pattern p = Pattern.compile(compile);
        Matcher matcher = p.matcher(content);
        if (matcher.find()) {
            group = matcher.group(0);
        }
        return group;
    }

    /**
     * 如果文本包含中括号（[海正]美罗培南针），取括号之后的文字
     *
     * @param str
     * @return
     */
    private String removeBracket(String str) {
        if (str.contains("]") && str.indexOf("]") != str.length() - 1) {
            return str.substring(str.indexOf("]") + 1);
        }
        return str;
    }

    /**
     * 拼接提示信息
     *
     * @param sb
     * @param drugKey
     * @param date
     */
    private void infoAppend(StringBuffer sb, String drugKey, String date) {
        sb.append(drugKey).append("(").append(DateUtil.formatDate(StringUtil.parseDateTime(date))).append(")").append(",");
    }

}
