package com.lantone.qc.kernel.util;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.lantone.qc.dbanaly.util.KernelConstants;
import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
import com.lantone.qc.kernel.catalogue.QCCatalogue;
import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
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.Diag;
import com.lantone.qc.pub.util.ListUtil;
import com.lantone.qc.pub.util.SpringContextUtil;
import com.lantone.qc.pub.util.StringUtil;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName : CatalogueUtil
 * @Description :
 * @Author : 楼辉荣
 * @Date: 2020-03-09 10:59
 */
@Getter
@Setter
public class CatalogueUtil {
    public static Map<String, QCCatalogue> qcCatalogueMap = new HashMap<>();
    public static Map<Integer, String> intMapString =
            ImmutableMap.<Integer, String>builder().put(1, "一").put(2, "二").put(3, "三").put(4, "四").put(5, "五")
                    .put(6, "六").put(7, "七").put(8, "八").put(9, "九").put(0, "零").build();

    public static boolean isEmpty(String content) {
        return StringUtil.isBlank(removeSpecialChar(content));
    }

    public static String removeSpecialChar(String content) {
        if (StringUtil.isEmpty(content)) {
            return "";
        }
        return content.replaceAll("[\r\n|\n|\t]", " ").trim();
    }

    public static String[] extractDigit(String value) {
        String[] res = new String[2];
        try {
            String regTime = "([\\d]+)([\\u4e00-\\u9fa5]+)";
            Pattern pattern = Pattern.compile(regTime);
            Matcher matcher = pattern.matcher(value);
            if (matcher.find(0)) {
                res[0] = matcher.group(1);
                res[1] = matcher.group(2);
            } else {
                res[0] = value;
                res[1] = "";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return res;
    }

    /**
     * words中的所有词，哪些不包含在text文本里的引号下面
     * 如：
     * word：{"高血压","糖尿病","白血病","感冒"}
     * text: 否认患有"高血压，糖尿病等"，"白血病",感冒
     * 结果：感冒
     *
     * @param words
     * @param text
     * @return
     */
    public static List<String> noInQuotes(List<String> words, String text) {
        List<String> retWords = Lists.newArrayList();
        if (ListUtil.isNotEmpty(words) && StringUtil.isNotBlank(text)) {
            List<String> sections = Lists.newArrayList();
            int index = 0;
            for (String txt : text.split("\"")) {
                if (index % 2 == 1 && text.indexOf("\"", text.indexOf(txt)) > -1) {
                    sections.add(txt);
                }
                index++;
            }
            for (String word : words) {
                if (StringUtil.isNotBlank(word)) {
                    String newWord = word.replaceAll("[“”]", "\"");
                    if (sections.stream().noneMatch(section -> section.contains(newWord))) {
                        retWords.add(word);
                    }
                }
            }
        }
        return retWords;
    }

    /**
     * 从现有诊断中筛选符合某一属性值的诊断
     *
     * @param diags
     * @param nature
     * @param natureValue
     * @return
     */
    public static List<Diag> filterDiagsByNature(List<Diag> diags, String nature, String natureValue) {
        if (ListUtil.isEmpty(diags) || StringUtil.isBlank(nature) || StringUtil.isBlank(natureValue)) {
            return null;
        }
        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
        Map<String, Map<String, String>> conceptDiagPropertyMap = specialStorageUtil.getJsonStringValue(KernelConstants.CONCEPT_DIAG_PROPERTY_MAP);
        if (conceptDiagPropertyMap == null) {
            return null;
        }
        List<Diag> retDiags = Lists.newArrayList();
        diags.forEach(i -> {
            if (i != null && StringUtil.isNotBlank(i.getHospitalDiagName())) {
                Map<String, String> diagDetailMap = conceptDiagPropertyMap.get(i.getHospitalDiagName());
                if (diagDetailMap != null) {
                    String natureValue_ = diagDetailMap.get(nature);
                    if (StringUtil.isNotBlank(natureValue_) && natureValue_.equals(natureValue)) {
                        retDiags.add(i);
                    }
                }
            }
        });
        return retDiags;
    }

    /**
     * 对比两个String类型的Date是否一致
     *
     * @param firstDateStr
     * @param secondDateStr
     * @param datePattren
     * @return
     */
    public static boolean equalsDate(String firstDateStr, String secondDateStr, String datePattren) {
        if (!isEmpty(firstDateStr) && !isEmpty(secondDateStr)) {
            Date firstDate = StringUtil.parseDateTime(firstDateStr);
            Date secondDate = StringUtil.parseDateTime(secondDateStr);
            SimpleDateFormat fmt = new SimpleDateFormat(datePattren);
            if (firstDate != null && secondDate != null && fmt.format(firstDate).equals(fmt.format(secondDate))) {
                return true;
            }
        }
        return false;
    }

    public static boolean equalsDate(Date firstDate, Date secondDate, String datePattren) {
        if (firstDate != null && secondDate != null) {
            SimpleDateFormat fmt = new SimpleDateFormat(datePattren);
            return fmt.format(firstDate).equals(fmt.format(secondDate));
        }
        return false;
    }

    /**
     * 对比两个String类型的Date先后
     *
     * @param firstDateStr
     * @param secondDateStr
     * @param symbol        =1 -> firstDateStr比secondDateStr时间早
     * @param symbol        =-1 -> firstDateStr比secondDateStr时间晚
     * @return
     */
    public static boolean compareDate(String firstDateStr, String secondDateStr, int symbol) {
        if (!isEmpty(firstDateStr) && !isEmpty(secondDateStr)) {
            Date firstDate = StringUtil.parseDateTime(firstDateStr);
            Date secondDate = StringUtil.parseDateTime(secondDateStr);
            if (symbol == 1) {
                return firstDate != null && secondDate != null && firstDate.before(secondDate);
            } else if (symbol == -1) {
                return firstDate != null && secondDate != null && firstDate.after(secondDate);
            }
        }
        return false;
    }

    /**
     * 对比两个去除了特殊字符的字符串是否一致
     *
     * @param firstStr
     * @param secondStr
     * @return
     */
    public static boolean compareToken(String firstStr, String secondStr) {
        if (!isEmpty(firstStr) && !isEmpty(secondStr)) {
            if (removeSpecialChar(firstStr).equals(removeSpecialChar(secondStr))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 比较时间,以分钟为单位
     * endDate比startDate多diff分钟则返回true
     *
     * @param startDate
     * @param endDate
     * @param diff
     * @return
     */
    public static boolean compareTime(Date startDate, Date endDate, Long diff) {
        boolean overtime = false;
        if (startDate == null || endDate == null) {
            return false;
        }
        Calendar calendar_s = Calendar.getInstance();
        Calendar calendar_e = Calendar.getInstance();
        Long time_s, time_e, time_diff;
        try {
            calendar_s.setTime(startDate);
            calendar_e.setTime(endDate);

            time_s = calendar_s.getTimeInMillis();
            time_e = calendar_e.getTimeInMillis();

            time_diff = (time_e - time_s) / (1000 * 60);
            if (time_diff > diff) {
                overtime = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return overtime;
    }

    /**
     * 获取查房记录标题中医师职称
     *
     * @return
     */
    public static String subTitle(String srcText) {
        if (StringUtil.isNotBlank(srcText) && srcText.contains("代")) {
            srcText = srcText.substring(srcText.lastIndexOf("代") + 1);
        }
        return srcText;
    }

    /**
     * 获取指定字符串出现的次数
     *
     * @param srcText  源字符串
     * @param findText 要查找的字符串
     * @return
     */
    public static int appearNumber(String[] srcText, String findText) {
        int count = 0;
        for (String title : srcText) {
            title = subTitle(title);
            if (title.contains(findText)) {
                count++;
            }
        }
        return count;
    }

    /**
     * 只保留Date数组中精确到分的格式
     *
     * @param dateFormats
     * @return
     */
    public static String[] processDateFormat(String[] dateFormats) {
        List<String> dateFormatsList = Arrays.asList(dateFormats);
        List<String> dateFormatsNew = new ArrayList<>(dateFormatsList);
        dateFormatsNew.removeIf(dateFormat -> !dateFormat.contains("m"));
        String[] dateFormatsArr = new String[dateFormatsNew.size()];
        return dateFormatsNew.toArray(dateFormatsArr);
    }

    /**
     * 判断字符串是否包含中文字
     *
     * @param str
     * @return
     */
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        return m.find();
    }

    /**
     * 判断字符串是否 仅 包含数字
     *
     * @param str
     * @return
     */
    public static boolean numbersOnly(String str) {
        String regex = "^[0-9]+$";
        return str.matches(regex);
    }

    /**
     * 判断文本是否包含数字
     *
     * @param str
     * @return
     */
    public static boolean numberExist(String str) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(str);
        return m.find();
    }

    /**
     * 判断是否为手术患者
     *
     * @param doctorAdviceDocs
     * @return
     */
    public static boolean isOperativePatients(List<DoctorAdviceDoc> doctorAdviceDocs) {
        String orderPrescriptionType, orderItemName;
        for (DoctorAdviceDoc doctorAdviceDoc : doctorAdviceDocs) {
            Map<String, String> doctorAdviceStructureMap = doctorAdviceDoc.getStructureMap();
            orderPrescriptionType = doctorAdviceStructureMap.get("医嘱处方类型");
            orderItemName = doctorAdviceStructureMap.get("医嘱项目名称");
            if (StringUtil.isNotBlank(orderPrescriptionType) && "手术".equals(orderPrescriptionType)) {
                return true;
            }
            if (StringUtil.isNotBlank(orderItemName) && Pattern.matches(".*拟.*术.*", orderItemName)
                    && !orderItemName.contains("冠脉造影")) {
                return true;
            }
        }
        return false;
    }

    public static String int2ChineseNum(String content) {
        StringBuffer sb = new StringBuffer();
        char[] contentArr = content.toCharArray();
        for (int i = 0; i < contentArr.length; i++) {
            if (isNumeric(contentArr[i])) {
                int num = Integer.parseInt(String.valueOf(contentArr[i]));
                sb.append(intMapString.get(num));
            } else {
                sb.append(contentArr[i]);
            }
        }
        return sb.toString();
    }


    public static boolean isNumeric(char c) {
        if (c < 48 || c > 57) {
            return false;
        }
        return true;
    }

    public static Date parseStringDate(String dateStr) {
        if (StringUtil.isBlank(dateStr)) {
            return null;
        }
        return StringUtil.parseDateTime(dateStr);
    }

    /**
     * 去除两个中文字之间空格
     *
     * @param str
     * @return
     */
    public static String removeBetweenWordSpace(String str) {
        Pattern pattern = Pattern.compile("(?<=[\\x{4e00}-\\x{9fa5}])\\s(?=[\\x{4e00}-\\x{9fa5}])");
        Matcher m = pattern.matcher(str);
        return m.replaceAll("");
    }

    /**
     * 获取两个时间的时间差
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static long timeDifference(Date firstDate, Date secondDate) {
        long timeDifference = 0L;
        if (firstDate == null || secondDate == null) {
            return timeDifference;
        }
        boolean flag = false;
        if (firstDate.before(secondDate)) {
            flag = true;
        }
        Calendar calendarS = Calendar.getInstance();
        Calendar calendarE = Calendar.getInstance();
        long timeS, timeE;
        try {
            calendarS.setTime(firstDate);
            calendarE.setTime(secondDate);

            timeS = calendarS.getTimeInMillis();
            timeE = calendarE.getTimeInMillis();

            if (flag) {
                timeDifference = (timeE - timeS) / (1000 * 60);
            } else {
                timeDifference = (timeS - timeE) / (1000 * 60);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return timeDifference;
    }

    /**
     * 获取主刀医师/一助职称(取距离查房记录时间最近的一次手术记录)
     *
     * @param operationDocs
     * @return
     */
    public static String getDoctorTitle(List<OperationDoc> operationDocs, Date recordDate, String findTitle) {
        String title = "";
        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
        Map<String, Object> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
        if (surgeon == null) {
            return title;
        }
        /* 用于存放手术结束时间距离查房时间最近的一次时间差 */
        long timeDiff = 0L;
        for (OperationDoc operationDoc : operationDocs) {
            OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
            if (operationRecordDoc == null) {
                continue;
            }
            Map<String, String> structureMap = operationRecordDoc.getStructureMap();
            String chiefSurgeon = structureMap.get(findTitle);
            String operatorEndDateStr = structureMap.get("手术结束时间");

            if (StringUtil.isBlank(chiefSurgeon) || StringUtil.isBlank(operatorEndDateStr)) {
                continue;
            }
            Map<String, String> doctor = (Map) surgeon.get(chiefSurgeon);
            if (doctor != null) {
                String professor = doctor.get("professor");
                Date operatorEndDate = StringUtil.parseDateTime(operatorEndDateStr);
                if (operatorEndDate != null) {
                    long timeDifference = timeDifference(operatorEndDate, recordDate);
                    if (timeDifference == 0) {
                        continue;
                    }
                    if (timeDiff == 0 || timeDiff > timeDifference) {
                        /* 取距离此次主刀医师查房最近的一次手术时间 */
                        timeDiff = timeDifference;
                        title = professor;
                    }
                }
            }
        }
        return title;
    }

    /**
     * 拼接结构化数据
     **/
    public static String structureMapJoin(Map<String, String> structureMap, List<String> keys) {
        String textJoin = "";
        for (String key : keys) {
            if (StringUtil.isNotBlank(structureMap.get(key))) {
                textJoin += key + "：" + structureMap.get(key) + "\n";
            }
        }
        return textJoin;
    }

    /**
     * 拼接info信息
     *
     * @param infoStr
     * @param content
     * @return
     */
    public static String concatInfo(String infoStr, String content) {
        if (StringUtil.isBlank(infoStr)) {
            infoStr += content;
        } else {
            if (!infoStr.contains(content)) {
                infoStr += "," + content;
            }
        }
        return infoStr;
    }

    /**
     * 判断是否是特殊字符：“-”，“/”,"\"
     *
     * @param str
     * @return
     */
    public static Boolean isSpecialChar(String str) {
        if (("-").equals(str) || ("\\").equals(str) || ("/").equals(str)) {
            return true;
        }
        return false;
    }

    /**
     * 获取医生职称 主治  主任......
     *
     * @param doctorSign
     * @return
     */
    public static String getProfessor(String doctorSign) {
        String professor = "";
        if (StringUtil.isBlank(doctorSign)) {
            return professor;
        }
        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
        Map<String, Map<String, String>> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
        if (surgeon != null) {
            Map<String, String> doctor = (Map) surgeon.get(doctorSign);
            if (doctor != null) {
                professor = doctor.get("professor");
            }
        }
        return professor;
    }

    /**
     * 判断医生是否是执业医师
     *
     * @param doctorSign
     * @return
     */
    public static boolean isOccup(String doctorSign) {
        if (StringUtil.isNotBlank(doctorSign)) {
            SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
            Map<String, Map<String, String>> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
            if (surgeon != null) {
                Map<String, String> doctor = (Map) surgeon.get(doctorSign);
                if (doctor != null) {
                    String occup = doctor.get("occup");
                    if (StringUtils.isNotEmpty(occup) && "1".equals(occup)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public static Set<String> getRegexWords(String word, String regex) {
        Set<String> ret = new HashSet<>();
        if (StringUtil.isNotBlank(word) && StringUtil.isNotBlank(regex)) {
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(word);
            if (matcher.find()) {
                ret.add(matcher.group().replaceAll("[\\[\\]（()）]", ""));
                int startIndex = matcher.start();
                int endIndex = matcher.end();
                if (startIndex > 0) {
                    ret.add(word.substring(0, startIndex));
                }
                if (endIndex <= word.length()) {
                    ret.addAll(getRegexWords(word.substring(endIndex), regex));
                }
            } else {
                ret.add(word);
            }
        }
        return ret;
    }

}