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.FirstCourseRecordDoc;
import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
import com.lantone.qc.pub.model.doc.consultation.ConsultationDoc;
import com.lantone.qc.pub.model.doc.operation.OperationDiscussionDoc;
import com.lantone.qc.pub.model.doc.operation.OperationDoc;
import com.lantone.qc.pub.model.doc.operation.OperationRecordDoc;
import com.lantone.qc.pub.model.entity.Drug;
import com.lantone.qc.pub.model.label.DrugLabel;
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-28 14:10
 * @desc 病程中抗生素记录不规范
 **/
@Component
public class THR03077 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();
        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
        List<ConsultationDoc> consultationDocs = inputInfo.getConsultationDocs();
        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
        if (doctorAdviceDocs.size() == 0) {
            return;
        }
        Map<Date, String> extData = null;
        if (outputInfo.getResult().get("THR02985") != null) {
            extData = (Map<Date, String>) outputInfo.getResult().get("THR02985").get("extData");
        }

        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("已停止"))
                .filter(x -> StringUtil.isNotBlank(x.get("给药方式")) && x.get("给药方式").contains("静脉滴注"))
                .filter(x -> StringUtil.isNotBlank(x.get("医嘱频率")) && !x.get("医嘱频率").equals("ONCE"))
                .collect(Collectors.toList());

        //抗生素及开医嘱时间(包括加用过抗生素的时间)     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();
        //记录同一天内是否开过多次同一抗生素
        Map<String, Map<Date, Integer>> antibioticDateTimes = Maps.newHashMap();
        String drugName = null, value = null, startDateStr = null;
        Date startDate = null;
        getAntibioticTimes(docAdvStruct, antibioticDateTimes);
        for (Map<String, String> structMap : docAdvStruct) {
            drugName = structMap.get("医嘱项目名称");
            value = structMap.get("医嘱单次剂量");
            startDateStr = structMap.get("医嘱开始时间");
//            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
            startDate = StringUtil.parseDateTime(startDateStr);
            if (StringUtil.isNotBlank(drugName)) {
                if (antibioticDateTimes.get(drugName).get(startDate) > 0) {
                    continue;   //一天内同一抗生素开过多次的抗生素直接过滤
                }
                drugName = removeBracket(drugName).replaceAll("[^\u4e00-\u9fa5]", "");
                String drugStandardWord = similarityUtil.getDrugStandardWord(drugName);
                if (StringUtil.isNotBlank(drugStandardWord)) {
                    drugName = drugStandardWord;
                }

                if (extData != null && extData.containsKey(startDate) && extData.get(startDate).equals(drugName)) {
                    continue;   //THR02985  医嘱有抗生素使用病程无记录，规则中没报未记录的抗生素继续走这条规则，报未记录的抗生素过滤
                }

                if (Arrays.asList(KSS).contains(drugName)) {
                    collectAntibioticInfo(antibioticDate, antibioticStatus, antibioticValue, drugName, value, startDateStr);
                }
            }
        }

        //把抗生素使用剂量没变化过的抗生素删除
        antibioticStatus.forEach((x, y) -> {
            if (y == 0) {
                antibioticDate.remove(x);
                antibioticValue.remove(x);
            }
        });
        //把同一天内同一个抗生素开过多次的抗生素删除
//        antibioticDateTimes.forEach((x, y) -> {
//            if (y > 0) {
//                antibioticDate.remove(x);
//                antibioticValue.remove(x);
//            }
//        });
        //抗生素加用过的集合如果为空，则一个抗生素都没有加用过，直接返回0
        if (antibioticDate.size() == 0) {
            return;
        }

        //病程记录中没有用量的抗生素及查房时间       key:抗生素名    "2020-08-20,2020-08-21 ..."
//        Map<String, Map<String, List<String>>> antibioticDateCourse = Maps.newHashMap();
        Map<String, List<String>> antibioticDateCourse = Maps.newHashMap();
        String dateStr = null;
        /*********************************************首程治疗计划********************************************************/
        if (firstCourseRecordDoc != null) {
            DrugLabel drugLabel = firstCourseRecordDoc.getDrugLabel();
            dateStr = firstCourseRecordDoc.getStructureMap().get("记录时间");
            if (drugLabel != null && StringUtil.isNotBlank(dateStr)) {
                List<Drug> drugs = drugLabel.getDrugs();
                getCourseDrugInfo(antibioticDateCourse, dateStr, drugs,
                        CatalogueUtil.structureMapJoin(firstCourseRecordDoc.getStructureMap(), Lists.newArrayList("治疗计划")),
                        "首次病程录");
            }
        }
        /*********************************************查房记录********************************************************/
        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, dateStr, drugs,
                        CatalogueUtil.structureMapJoin(doc.getStructureMap(), Lists.newArrayList("病情记录", "治疗计划和措施")),
                        "查房记录");
            }
        }
        /*********************************************手术记录、术后首程************************************************/
        if (operationDocs.size() > 0) {
            //手术记录
            List<OperationRecordDoc> operationRecordDocs = operationDocs
                    .stream()
                    .map(OperationDoc::getOperationRecordDoc)
                    .filter(Objects::nonNull)
                    .filter(x -> x.getOperationRecordLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
                    .collect(Collectors.toList());
            operationRecordDocs.forEach(x -> getCourseDrugInfo(antibioticDateCourse, x.getStructureMap().get("病历日期"), x.getOperationRecordLabel().getDrugs()
                    , CatalogueUtil.structureMapJoin(x.getStructureMap(), Lists.newArrayList("手术经过")),
                    "手术记录"));
            List<OperationDiscussionDoc> operationDiscussionDocs = operationDocs
                    .stream()
                    .map(OperationDoc::getOperationDiscussionDoc)
                    .filter(Objects::nonNull)
                    .filter(x -> x.getOperationDiscussionLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("记录日期")))
                    .collect(Collectors.toList());
            operationDiscussionDocs.forEach(x -> getCourseDrugInfo(antibioticDateCourse, x.getStructureMap().get("记录日期"), x.getOperationDiscussionLabel().getDrugs()
                    , CatalogueUtil.structureMapJoin(x.getStructureMap(), Lists.newArrayList("手术经过", "治疗计划和措施")),
                    "术后首次病程录"));
        }
        /*********************************************会诊结果单********************************************************/
        /*if (consultationDocs.size() > 0) {
            List<ConsultationResultsDoc> consultationResultsDocs = consultationDocs
                    .stream()
                    .map(ConsultationDoc::getConsultationResultsDoc)
                    .filter(Objects::nonNull)
                    .filter(x -> x.getConsultationResultLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("会诊日期及时间")))
                    .collect(Collectors.toList());
            consultationResultsDocs.forEach(x -> getCourseDrugInfo(antibioticDateCourse, x.getStructureMap().get("会诊日期及时间"), x.getConsultationResultLabel().getDrugs()
                    , CatalogueUtil.structureMapJoin(x.getStructureMap(), Lists.newArrayList("会诊意见"))));
        }*/
        /*********************************************出院小结********************************************************/
        if (leaveHospitalDoc != null) {
            LeaveHospitalLabel leaveHospitalLabel = leaveHospitalDoc.getLeaveHospitalLabel();
            dateStr = leaveHospitalDoc.getStructureMap().get("出院时间");
            if (leaveHospitalLabel != null && StringUtil.isNotBlank(dateStr)) {
                List<Drug> drugs = leaveHospitalLabel.getDrugs();
                getCourseDrugInfo(antibioticDateCourse, dateStr, drugs
                        , CatalogueUtil.structureMapJoin(leaveHospitalDoc.getStructureMap(), Lists.newArrayList("诊治经过", "出院带药")),
                        "出院小结");
            }
        }

        //将病程日期排序
        antibioticDateCourse.forEach((x, y) -> y.sort(Comparator.naturalOrder()));

        /**
         * 1.antibioticDate：从医嘱中取   key：抗生素名    value：医嘱中该抗生素所有剂量变化的时间（包括初始使用时间）
         * 2.antibioticDateWard：从查房记录中取     key：抗生素名    value：病程记录中该抗生素所有没有用量时的查房时间（包括初始使用时间）
         */
        String drugKey = null, source = null;
        Map<String, Map<String, List<String>>> sourceDateMap = Maps.newHashMap();
        String[] date_missInfo = null;
        for (Map.Entry<String, List<String>> ad : antibioticDate.entrySet()) {
            drugKey = ad.getKey();
            drugKey = removeBracket(drugKey).replaceAll("[^\u4e00-\u9fa5]", "");
            String drugStandardWord = similarityUtil.getDrugStandardWord(drugKey);
            if (StringUtil.isNotBlank(drugStandardWord)) {
                drugKey = drugStandardWord;
            }
            if (antibioticDateCourse.containsKey(drugKey)) {
                for (Map.Entry<String, List<String>> adc : antibioticDateCourse.entrySet()) {
                    if (adc.getKey().equals(drugKey)) {
                        List<String> dateMissInfos = adc.getValue();
                        for (String dateMissInfo : dateMissInfos) {
                            StringBuffer sb = new StringBuffer();
                            date_missInfo = dateMissInfo.split("=");
                            source = date_missInfo[2];
                            sb.append(source).append("=").append(date_missInfo[0]).append("=").append(date_missInfo[1]);

                            if (date_missInfo.length > 0) {
                                if (sourceDateMap.containsKey(source)) {
                                    Map<String, List<String>> drugData = sourceDateMap.get(source);
                                    if (drugData.containsKey(drugKey)) {
                                        drugData.get(drugKey).add(sb.toString());
                                    } else {
                                        drugData.put(drugKey, Lists.newArrayList(sb.toString()));
                                    }
                                } else {
                                    Map<String, List<String>> drugData = Maps.newHashMap();
                                    drugData.put(drugKey, Lists.newArrayList(sb.toString()));
                                    sourceDateMap.put(source, drugData);
                                }
                            }
                        }
                    }
                }
            }
        }

        //表示提示信息
        if (sourceDateMap.size() > 0) {
            infoDisplay(sourceDateMap, source, drugKey);
        }

    }

    /**
     * 表示提示信息
     *
     * @param sourceDateMap
     */
    private void infoDisplay(Map<String, Map<String, List<String>>> sourceDateMap, String source, String drugKey) {
        StringBuffer strBuf = new StringBuffer();
        List<String> dateList = null;

        for (Map.Entry<String, Map<String, List<String>>> ad : sourceDateMap.entrySet()) {
            source = ad.getKey();
            Map<String, List<String>> drugInfo = ad.getValue();
            strBuf.append(source).append("(");
            for (Map.Entry<String, List<String>> drug : drugInfo.entrySet()) {
                drugKey = drug.getKey();
                strBuf.append(drugKey).append(":");
                dateList = drug.getValue();
                for (String date_miss : dateList) {
                    String[] date_miss_nfo = date_miss.split("=");
                    strBuf.append(DateUtil.formatDateTime(StringUtil.parseDateTime(date_miss_nfo[1]))).append(",").append(date_miss_nfo[2]).append("、");
                }
            }

            strBuf.deleteCharAt(strBuf.length() - 1);
            strBuf.append(")").append("、");

        }

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

    /**
     * 记录同一抗生素同一天内是否开过多次，用于医嘱中需要处理的抗生素过滤（一天内同一抗生素开过多次的抗生素直接过滤）
     *
     * @param docAdvStruct
     * @param antibioticDateTimes
     */
    private void getAntibioticTimes(List<Map<String, String>> docAdvStruct, Map<String, Map<Date, Integer>> antibioticDateTimes) {
        String drugName;
        String startDateStr;
        Date startDate;
        Map<Date, Integer> antibioticDateTime;
        for (Map<String, String> structMap : docAdvStruct) {
            drugName = structMap.get("医嘱项目名称");
            startDateStr = structMap.get("医嘱开始时间");
//            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
            startDate = StringUtil.parseDateTime(startDateStr);
            if (antibioticDateTimes.containsKey(drugName)) {
                Map<Date, Integer> map = antibioticDateTimes.get(drugName);
                if (map.containsKey(startDate)) {
                    map.put(startDate, map.get(startDate) + 1);
                } else {
                    map.put(startDate, 0);
                }
            } else {
                antibioticDateTime = Maps.newHashMap();
                antibioticDateTime.put(startDate, 0);
                antibioticDateTimes.put(drugName, antibioticDateTime);
            }
        }
    }

    /**
     * 收集各模块药品信息
     *
     * @param antibioticDateWard 病程中没有用量+用法+频率的抗生素使用所有时间
     * @param dateStr            记录日期
     * @param drugs              模型提取出的药品列表
     */
    private void getCourseDrugInfo(Map<String, List<String>> antibioticDateWard, String dateStr, List<Drug> drugs, String content, String source) {
        StringBuffer sb = null;
        for (Drug drug : drugs) {
            sb = new StringBuffer();
            //现**感染、建议**更换，更改，改为带有抗生素的过滤掉
            boolean findDrug = MissDrug(content);
            if (findDrug) {
                continue;
            }
            String wardDrug = drug.getName();
            int position = content.indexOf(wardDrug);
            String keyword = content.substring(Math.max(0, position - 10), position);
            if (keyword.contains("继续") || keyword.contains("停")) {
                continue;
            }
            wardDrug = removeBracket(wardDrug);
            String drugStandardWord = similarityUtil.getDrugStandardWord(wardDrug);
            if (StringUtil.isNotBlank(drugStandardWord)) {
                wardDrug = drugStandardWord;
            }
            if (drug.getConsumption() == null) {
                concatInfo(dateStr, sb, "用量");
            }
            if (drug.getUsageWardRound() == null) {
                concatInfo(dateStr, sb, "用法");
            }
            if (drug.getFrequency() == null) {
                concatInfo(dateStr, sb, "频率");
            }
            if (sb.toString().length() > 0) {
                sb.append("=").append(source);
                if (antibioticDateWard.containsKey(wardDrug)) {
                    antibioticDateWard.get(wardDrug).add(sb.toString());
                } else {
                    antibioticDateWard.put(wardDrug, Lists.newArrayList(sb.toString()));
                }
            }
        }
    }

    /**
     * 现**感染、建议**更换，更改，改为带有抗生素的过滤掉
     *
     * @param content
     * @return
     */
    private boolean MissDrug(String content) {
        boolean findDrug = false;
        int preInf = content.indexOf("现");
        int proCha = content.indexOf("建议");
        if (preInf > 0) {
            String preInfected = content.substring(preInf);
            if (preInfected.contains("感染")) {
                findDrug = true;
            }
        }
        if (proCha > 0) {
            String proChange = content.substring(proCha);
            if (proChange.contains("更换") || proChange.contains("更改") || proChange.contains("改为")) {
                findDrug = true;
            }
        }
        return findDrug;
    }


    /**
     * 拼接抗生素缺失信息
     *
     * @param dateStr
     * @param sb
     */
    private void concatInfo(String dateStr, StringBuffer sb, String missType) {
        if (sb.toString().contains("=")) {
            sb.append(",").append(missType);
        } else {
            sb.append(dateStr).append("=").append(missType);
        }
    }

    /**
     * 收集抗生素各种信息
     *
     * @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("THR03077:       " + 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 {
            //1.如果抗生素剂量有变化，则记录该抗生素开始时间
            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);
                return;
            }
            //2.如果抗生素剂量两次开启的时间间隔相差3天，也记录该抗生素开始时间
            List<String> currentAntibioticDate = antibioticDate.get(drugName);
            if (currentAntibioticDate.size() > 0) {
                String lastDate = currentAntibioticDate.get(currentAntibioticDate.size() - 1);
                if (CatalogueUtil.compareTime(StringUtil.parseDateTime(lastDate), StringUtil.parseDateTime(startDateStr), 72 * 60L)) {
                    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;
    }

    private static final String[] KSS = {
            "万古霉素",
            "两性霉素B",
            "亚胺培南西司他丁",
            "伊曲康唑",
            "伏立康唑",
            "依替米星氯化钠",
            "克拉霉素",
            "克林霉素",
            "利奈唑胺",
            "利奈唑胺葡萄糖",
            "利福昔明",
            "制霉菌素",
            "卡泊芬净",
            "厄他培南",
            "吗啉硝唑氯化钠",
            "呋喃唑酮",
            "哌拉西林他唑巴坦",
            "复方磺胺甲噁唑",
            "多粘菌素B",
            "多西环素",
            "夫西地酸",
            "头孢丙烯",
            "头孢他啶",
            "头孢他啶阿维巴坦",
            "头孢他美酯",
            "头孢克洛",
            "头孢克肟",
            "头孢吡肟",
            "头孢呋辛",
            "头孢哌酮舒巴坦",
            "头孢唑林",
            "头孢噻肟",
            "头孢地嗪",
            "头孢地尼",
            "头孢拉定",
            "头孢曲松",
            "头孢替安",
            "头孢美唑",
            "头孢西丁",
            "奥硝唑",
            "妥布霉素",
            "妥布霉素地塞米松",
            "左氧氟沙星",
            "左氧氟沙星氯化钠",
            "庆大霉素",
            "异帕米星",
            "拉氧头孢",
            "替加环素",
            "替硝唑",
            "替考拉宁",
            "比阿培南",
            "氟康唑",
            "氟康唑氯化钠",
            "氟胞嘧啶",
            "氨曲南",
            "氨苄西林",
            "泊沙康唑",
            "特比萘芬",
            "甲硝唑",
            "甲硝唑氯化钠",
            "磷霉素",
            "磷霉素氨丁三醇",
            "米卡芬净",
            "米诺环素",
            "红霉素",
            "美罗培南",
            "苄星青霉素",
            "莫西沙星",
            "莫西沙星氯化钠",
            "达托霉素",
            "阿奇霉素",
            "阿奇霉素枸橼酸二氢钠",
            "阿洛西林",
            "阿米卡星",
            "阿莫西林",
            "阿莫西林克拉维酸",
            "青霉素"
    };
}
