package org.diagbot.common.push.filter;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.diagbot.common.push.bean.FeatureRate;
import org.diagbot.common.push.bean.ResponseData;
import org.diagbot.common.push.cache.CacheUtil;
import org.diagbot.nlp.relation.module.Lis;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Stream;

/**
 * Created by kwz on 2019/8/5.
 */
public class ClassifyDiag {
    //诊断-->部门
    Map<String, String>  diagDepartCache     = CacheUtil.getDiagDepartCache();
    //get diagClassifyCache
    Map<String, String>  diagClassifyCache   = CacheUtil.getDiagClassifyCache();
    //每个诊断所在的级别缓存
    Map<String, Integer> diagClassifyJiCache = CacheUtil.getDiagClassifyJiCache();

    /**
     * 根据诊断依据规则过滤诊断
     * @param graphResponseData 把过滤的诊断包装在这个对象里
     * @param graphFeatures 过滤前的诊断结果
     * @return 返回过滤后的诊断结果
     */
    public List<FeatureRate> filterDiag(ResponseData graphResponseData, List<FeatureRate> graphFeatures){
        //根据诊断依据规则过滤掉的诊断列表
        List<String> excludeDiag = graphResponseData.getExcludeDiag();
        //将需要排除的诊断从列表中删除
        List<FeatureRate> updateFeatures = new ArrayList<>();
        if(excludeDiag != null){
            for(int j = 0;j<graphFeatures.size();j++){
                if(excludeDiag.indexOf(graphFeatures.get(j).getFeatureName()) == -1){
                    updateFeatures.add(graphFeatures.get(j));
                }
            }
            return updateFeatures;
        }else {
            return graphFeatures;
        }

    }

    /**
     * 诊断归一
     * @param updateFeatures 归一前的诊断
     * @return 归一后的诊断
     */
    public List<FeatureRate> diagClassify(List<FeatureRate> updateFeatures){
        List<FeatureRate> finalDiagList = new LinkedList<>();//最终返回
        List<String> highDiagList = new LinkedList<>();//警惕集合
        List<String> diffDiagList = new LinkedList<>();//鉴别诊断集合
        List<String> queDiagList = new LinkedList<>();//确诊集合
        List<String> bigDiagList = new LinkedList<>();//可能诊断集合
        if(updateFeatures != null && updateFeatures.size()>0){
            for(FeatureRate featureRate:updateFeatures){
                String featureName = featureRate.getFeatureName();
                String desc = featureRate.getDesc();
                Map<String,Object> d = new HashMap<>();
                if(desc != null){
                   if(desc.contains("确诊") || desc.contains("拟诊")){
                       queDiagList.add(featureName);
                   }else {
                       highDiagList.add(featureName);
                   }
                }else {
                    bigDiagList.add(featureName);
                }
            }
        }
        //先把警惕的加进去
        if(highDiagList.size()>0){
            for(int j =0;j<updateFeatures.size();j++){
                FeatureRate featureRate = updateFeatures.get(j);
                String featureName = featureRate.getFeatureName();
                int i = highDiagList.indexOf(featureName);
                if(i >= 0 && featureRate.getDesc() != null){
                    finalDiagList.add(featureRate);
                }
            }
        }
        //再把鉴别诊断加进去
        if(diffDiagList.size()>0){
            for(int j =0;j<updateFeatures.size();j++){
                FeatureRate featureRate = updateFeatures.get(j);
                String featureName = featureRate.getFeatureName();
                int i = diffDiagList.indexOf(featureName);
                if(i >= 0 && featureRate.getDesc() != null){
                    finalDiagList.add(featureRate);
                }
            }
        }
        /**
         * 这里处理一下可能诊断剔除的功能
         * 如果图谱推出的诊断和可能诊断有层级关系，就把对应的可能诊断剔除
         */
        Set<String> queSet =null;
        List<String> newBIgDiagList = this.removeKeng(queDiagList, bigDiagList);
        System.out.println("图谱归一前数据 ："+queDiagList);
        if(queDiagList != null && queDiagList.size()>0){
            //图谱归一 ,图谱sign =0,大数据sign = 1
            List<String> que = this.processQue(updateFeatures, queDiagList);
            queSet = this.diagProcess(que,0);
            System.out.println("图谱归一后的数据    ："+queSet);
            if(queSet != null && queSet.size()>0){
                for (String queDis:queSet) {
                    if(queDiagList.indexOf(queDis)>=0){ //可以找到，就取出来，用原来的
                        FeatureRate feature = this.getFeature(updateFeatures, queDis);
//                        if(feature.getDesc().contains("拟诊")){
                            feature.setDesc(feature.getDesc());
//                        }
                        feature.setExtraProperty(diagDepartCache.get(queDis));
                        finalDiagList.add(feature);
                    }else {
                        FeatureRate featureRate = new FeatureRate();
                        featureRate.setFeatureName(queDis);
                        featureRate.setDesc("{\"确诊\":\"\"}");
                        featureRate.setExtraProperty(diagDepartCache.get(queDis));
                        featureRate.setSource("neo4j");
                        finalDiagList.add(featureRate);
                    }
                }
            }
        }


        if(newBIgDiagList!= null && newBIgDiagList.size()>0){
            //大数据的可能诊断归一和排序
            List<FeatureRate> featureRates = this.sortFeatureList(newBIgDiagList, updateFeatures);
            //把可能诊断中和图谱相同的诊断去除
            if(featureRates != null && featureRates.size()>0 && queSet !=null){
                for (FeatureRate f:featureRates) {
                    if(queSet.contains(f.getFeatureName())){
                        featureRates.remove(f);
                        continue;
                    }
                }
            }
            finalDiagList.addAll(featureRates);
        }

        return finalDiagList;

    }

    /**
     * 诊断排序（诊断分为I类和II类，I类在前，II类在后，没有分类的诊断认为是I类）
     * @param updateFeatureRates  //入参（通过过滤条件过滤后）
     * @return
     */
    public List<FeatureRate> sortDiag(List<FeatureRate> updateFeatureRates){
        Map<String, String> diagSortCache = CacheUtil.getDiagSortCache();
        List<String> finalDiagList = new LinkedList<>();
        List<String> neoDiagList = new LinkedList<>();
        List<String> bigDataIDiagList = new LinkedList<>();
        List<String> bigDataIIDiagList = new LinkedList<>();
        List<FeatureRate> finalDiagFeature = new LinkedList<>();
        if(updateFeatureRates != null || updateFeatureRates.size()>0){
            for (FeatureRate feature:updateFeatureRates) {
                String featureName = feature.getFeatureName();
                String source = feature.getSource();
                if("neo4j".equals(source)){
                    neoDiagList.add(featureName);
                }else {
                    String s = diagSortCache.get(featureName);
                    if(StringUtils.isNotEmpty(s)){
                        if("Ⅰ".equals(s)){
                            bigDataIDiagList.add(featureName);
                        }else if("Ⅱ".equals(s)){
                            bigDataIIDiagList.add(featureName);
                        }else {
                            bigDataIDiagList.add(featureName);
                        }
                    }else {
                        bigDataIDiagList.add(featureName);
                    }
                }
            }
        }
//        finalDiagList.addAll(neoDiagList);
        finalDiagList.addAll(bigDataIDiagList);
        finalDiagList.addAll(bigDataIIDiagList);
        if(neoDiagList !=null && neoDiagList.size()>0){
            for (String diag:neoDiagList) {
                for (FeatureRate feature:updateFeatureRates) {
                    if(diag.equals(feature.getFeatureName())&& "neo4j".equals(feature.getSource())){
                        finalDiagFeature.add(feature);
                        break;
                    }
                }
            }
        }
        if(finalDiagList != null && finalDiagList.size()>0){
            for (String diag:finalDiagList){
                for (FeatureRate f:updateFeatureRates) {
                    if(diag.equals(f.getFeatureName())&& f.getSource()==null){
                        finalDiagFeature.add(f);
                        break;
                    }
                }
            }
        }
        return finalDiagFeature;
    }

    /**
     * 去除可能诊断和确诊有关系的诊断
     * @param queDiagList
     * @param bigDiagList
     * @return
     */
    public List<String> removeKeng(List<String> queDiagList,List<String> bigDiagList){
        List<String> bigList = new ArrayList<>();
        Set<String> queAll = new HashSet<>();
        if(queDiagList.size()>0 && bigDiagList.size()>0){
            for (String dis:queDiagList) {
                String s = diagClassifyCache.get(dis);
                if(s != null){
                    queAll.add(s);
                    List<Object> key = this.getKey(diagClassifyCache, s);
                    if(key.size()>0){
                        for (Object o:key
                             ) {
                            queAll.add(o.toString());
                        }
                    }
                }
                queAll.add(dis);
                List<Object> key = this.getKey(diagClassifyCache, dis);
                if(key != null && key.size()>0){
                    for (Object o:key) {
                        queAll.add(o.toString());
                        List<Object> key1 = this.getKey(diagClassifyCache, o.toString());
                        if(key1 !=null && key1.size()>0){
                            for (Object o1:key1
                                 ) {
                                queAll.add(o1.toString());
                            }
                        }
                    }

                }

            }
        }
        System.out.println(queAll);
        String[] strings = queAll.stream().toArray(String[]::new);
        if(bigDiagList != null && bigDiagList.size()>0){
            for (String dis:bigDiagList) {
                if(Arrays.asList(strings).indexOf(dis) == -1){
                    bigList.add(dis);
                }
            }
        }
        return bigList;
    }





    /**
     * 诊断归一和排序
     * @param disList
     * @return
     */
    public Set<String> diagProcess(List<String> disList,int sign){
        Set<String> first = new LinkedHashSet<>();
        Set<String> second= new LinkedHashSet<>();
        Set<String> third= new LinkedHashSet<>();
        Set<String> other= new LinkedHashSet<>();

        /**
         * 分级
         * 初始化每个病出现的次数为0
         */
        Map<String, Integer> children_cnt = new HashMap<>();
        for (String dis:disList) {
            Integer ji = diagClassifyJiCache.get(dis);
            if(ji != null){
                if(1 == ji){
                    first.add(dis);
                    children_cnt.put(dis,0);
                }else if(2 == ji){
                    second.add(dis);
                    children_cnt.put(dis,0);
                }else if(3 == ji){
                    third.add(dis);
                    children_cnt.put(dis,0);
                }
            }else {
                other.add(dis);
            }
        }
        /**
         * 从孙子找父亲，根据父亲找爷爷
         */
        if(third != null && third.size()>0){
            for (String dis:third) {
                String s = diagClassifyCache.get(dis);
                Integer count = children_cnt.get(s);
                if(s != null){
                    children_cnt.put(s,(count == null)?1:count+1);
                    second.add(s);
                }

            }
        }

        if(second != null && second.size()>0){
            for (String dis:second) {
                String s = diagClassifyCache.get(dis);
                Integer count = children_cnt.get(s);
                if(s != null){
                    children_cnt.put(s,(count == null)?1:count+1);
                    first.add(s);
                }
            }
        }
        List<String> pushDiag = new ArrayList<>();
        //从顶级往下级依次看
        for (String dis:first) {
            Integer count = children_cnt.get(dis);
            if(count == 0){
                pushDiag.add(dis);
            }else if(count == 1){
                List<Object> key = this.getKey(diagClassifyCache, dis);
                for (String diss:second) {
                    Integer c2 = children_cnt.get(diss);
                    if(key.contains(diss)){
                        if(c2 == 0){
                            pushDiag.add(diss);
                        }else if(c2 == 1){
                            List<Object> key1 = this.getKey(diagClassifyCache, diss);
                            for (String disss:third) {
                                if(key1.contains(disss)){
                                    pushDiag.add(disss);
                                }
                            }
                        }else if(c2 >1){
                            pushDiag.add(diss);
                        }
                    }

                }
            }else if(count >1){
                pushDiag.add(dis);
            }

        }
        pushDiag.addAll(other); //归一后的

        Set<String> finalList = new LinkedHashSet<>();
        if(sign == 0){
            finalList.addAll(pushDiag);
        }else if(sign == 1){
            for (String dis:disList) {
                int i = pushDiag.indexOf(dis);
                if(i >= 0){
                    finalList.add(dis);

                }else {
                    List<Object> testList= new ArrayList<>();
                    String s = diagClassifyCache.get(dis);
                    if(StringUtils.isNotEmpty(s)){
                        testList.add(s);
                    }
                    List<Object> key = this.getKey(diagClassifyCache, dis);
                    boolean b = testList.addAll(key);
                    for (Object dis1:testList) {
                        if(pushDiag.indexOf(dis1)>=0){
                            finalList.add(dis1.toString());

                        }
                    }
                }
            }
        }

        return finalList;

    }

    /**
     * 根据rate排序
     * @param diss 大数据可能诊断列表
     * @param updates 所有推送的诊断
     * @return 排好序并且归一的可能诊断列表
     */
    public List<FeatureRate> sortFeatureList(List<String> diss,List<FeatureRate> updates){
        DecimalFormat df = new DecimalFormat("0.####");
       List<FeatureRate> sortFeatures = new LinkedList<>();
        Set<String> strings = this.diagProcess(diss,1);

        Map<String,Double> disRate = new HashMap<>();
        //归一确诊
        if(diss!= null &&diss.size()>0){
            //归一后的确诊（图谱出来的）

            if(strings != null && strings.size()>0){
                for (String queDis:strings) {
                    List<Object> testCollect = new ArrayList<>();
//                    FeatureRate feature = classifyDiag.getFeature(inintFeature, queDis);
                    //如果能找到就把相关联的rate加起来
                    testCollect.add(queDis);

                    String s = null;
                    s= diagClassifyCache.get(queDis);
                    if(s != null){
                        testCollect.add(s);
                        s = diagClassifyCache.get(s);
                        if(s != null){
                            testCollect.add(s);
                        }
                    }
                    List<Object> key =null;
                    key = this.getKey(diagClassifyCache, queDis);
                    testCollect.addAll(key);
                    if(key != null && key.size()>0){
                        for (Object o:key) {
                            key = this.getKey(diagClassifyCache,o.toString());
                            if(key!= null){
                                testCollect.addAll(key);
                            }
                        }
                    }
                    Double count = 0.0;
                    for (String dis:diss) {
                        if(testCollect.indexOf(dis) >= 0){
                            FeatureRate feature1 = this.getFeature(updates, dis);
                            String rate1 = feature1.getRate();
                            count = count+Double.parseDouble(rate1);
                        }
                    }
                    disRate.put(queDis,count);
                }
            }

        }
        //根据rate排序
        List<Map.Entry<String,Double>> list = new ArrayList<>(disRate.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Double>>() {
            @Override
            public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        for (Map.Entry<String,Double> s:list) {
            System.out.println(s.getKey()+"\t"+s.getValue());
            FeatureRate featureRate = new FeatureRate();
            featureRate.setRate(df.format(s.getValue()));
            featureRate.setFeatureName(s.getKey());
            featureRate.setExtraProperty(diagDepartCache.get(s.getKey()));
            sortFeatures.add(featureRate);
        }

        return sortFeatures;
    }

    /**
     * 根据诊断名找到这个feature
     * @param updateFeatures
     * @param disName
     * @return
     */
    public FeatureRate getFeature(List<FeatureRate> updateFeatures,String disName){
        FeatureRate f = new FeatureRate();
        for (FeatureRate fe:updateFeatures){
            if(disName.equals(fe.getFeatureName())){
                f = fe;
            }
        }
        return f;
    }

    /**
     * dis找大类
     * @param inputs
     * @return
     */
    public List<String> getDisList(List<String> inputs){
        List<String> newDiagList = new ArrayList<>();
        if(inputs!= null && inputs.size()>0){
            for (String dis:inputs) {
                String s = diagClassifyCache.get(dis);
                if(StringUtils.isNotEmpty(s)){
                    newDiagList.add(s);
                }else {
                    newDiagList.add(dis);
                }

            }
        }
        return newDiagList;
    }

    /**
     * 统计列表中每个字符出现的次数
     * @param inputs 输入列表
     * @return
     */
    public Map<String,Integer> fildCount(List<String> inputs){
        Map<String,Integer> map = new HashMap<>();
        for (String dis:inputs) {
            Integer count = map.get(dis);
            map.put(dis,(count == null)?1:count+1);
        }
        return map;
    }

    public List<Object>  getKey(Map map, Object value){
        Set set = map.entrySet(); //通过entrySet()方法把map中的每个键值对变成对应成Set集合中的一个对象
        Iterator<Map.Entry<Object, Object>> iterator = set.iterator();
        List<Object> arrayList = new ArrayList();
        while(iterator.hasNext()){
            //Map.Entry是一种类型，指向map中的一个键值对组成的对象
            Map.Entry<Object, Object> entry = iterator.next();
            if(entry.getValue().equals(value)){
                arrayList.add(entry.getKey());
            }
        }
        return arrayList;
    }
    //归一有确诊的诊断
    public  List<String> processQue(List<FeatureRate> updateFeatures,List<String>queList){
        List<String> finallyQue = new LinkedList<>();
        List<String> que = new ArrayList<>();
        List<String> ni = new ArrayList<>();
        for (String qd:queList) {
            for (FeatureRate f:updateFeatures) {
                if("neo4j".equals(f.getSource()) && qd.equals(f.getFeatureName())){
                    if(f.getDesc().contains("确诊")){
                        que.add(qd);
                    }else if(f.getDesc().contains("拟诊")) {
                        ni.add(qd);
                    }
                }
            }
        }
        if(que != null && que.size()>0){
            for (String q:que) {
                Set<String> classifySet = new HashSet<>();
                String s = diagClassifyCache.get(q);
                if(StringUtils.isNotEmpty(s)){
                    classifySet.add(s);
                    List<Object> key = this.getKey(diagClassifyCache, s);
                    if(key != null && key.size()>0){
                        for (Object o:key) {
                            classifySet.add(o.toString());
                            List<Object> key1 = this.getKey(diagClassifyCache, o.toString());
                            if(key1 != null && key1.size()>0){
                                for (Object f:key1
                                     ) {
                                    classifySet.add(f.toString());
                                }
                            }
                        }
                    }
                }
                List<Object> key = this.getKey(diagClassifyCache, q);
                if(key != null && key.size()>0){
                    for (Object o:key) {
                        classifySet.add(o.toString());
                    }
                }
                if(classifySet != null && classifySet.size()>0){
                    for (String sq:classifySet
                         ) {
                        if(ni.indexOf(sq) >= 0){
                            ni.remove(sq);
                        }
                    }
                }
            }
        }
        finallyQue.addAll(que);
        finallyQue.addAll(ni);
        return finallyQue;

    }

}
