package com.lantone.qc.kernel.structure.ai.model;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Description: 找出冲突
 * @Author: HUJING
 * @Date: 2020/8/2 15:04
 */
public class ConflictFinder {

    private static Set<String> ignoreWords;
    private static Set<String> negativeWords;
    private static Map<String, String> conflictWordPairMap;

    static {
        ignoreWords = Sets.newHashSet("部", "侧");
        negativeWords = Sets.newHashSet("无", "无殊", "否认", "不伴", "未找到",
                "未萌出", "未见", "未", "不", "不伴有", "非", "不明显", "无明显");
        conflictWordPairMap = Maps.newHashMap();
        conflictWordPairMap.put("可", "差");
        conflictWordPairMap.put("尚可", "差");
    }


    /**
     * 搜索和配对
     *
     * @param invertedIndexTableCheck   专科检查的倒排索引
     * @param invertedIndexTablePresent 现病史的倒排索引
     */
    public List<EntityBlock[]> match(Map<String, Set<EntityBlock>> invertedIndexTableCheck,
                                     Map<String, Set<EntityBlock>> invertedIndexTablePresent) {

        List<EntityBlock[]> entityBlockPairs = Lists.newArrayList();
        Set<String> existedIdPairs = Sets.newHashSet();  // 去除多搜索词搜到同一组实体块对引起的重复
        invertedIndexTableCheck.forEach((char_, entityBlockSetCheck) -> {
            invertedIndexTablePresent.getOrDefault(char_, Sets.newHashSet()).forEach(entityBlockPresent -> {
                entityBlockSetCheck.forEach(entityBlockCheck -> {
                    String idPair = "" + entityBlockCheck.getId() + "_" + entityBlockPresent.getId();
                    if (!existedIdPairs.contains(idPair)) {
                        entityBlockPairs.add(new EntityBlock[] { entityBlockCheck, entityBlockPresent });

                        existedIdPairs.add(idPair);
                    }
                });
            });
        });

        return entityBlockPairs;
    }

    /**
     * 字符串1没在字符串2中的子词, // 并不是很严格意义上的那种，不过可以用
     *
     * @param word1 字符串1
     * @param word2 字符串2
     * @return 字符串列表
     */
    private List<String> subWordsInWord1NotInWord2(String word1, String word2) {

        StringBuilder inWord1NotInWord2 = new StringBuilder();
        Map<String, Integer> word2Map = Maps.newHashMap();
        for (int i = 0; i < word2.length(); i++) {
            word2Map.put(word2.substring(i, i + 1), 1);
        }

        for (int i = 0; i < word1.length(); i++) {
            String char_ = word1.substring(i, i + 1).trim();
            if (!"".equals(char_) && !ignoreWords.contains(char_)) {
                if (!word2Map.containsKey(char_)) {
                    inWord1NotInWord2.append(char_);
                } else {
                    inWord1NotInWord2.append("_s_");  // _s_ 作为分隔符
                }
            }
        }
        List<String> subWords = Lists.newArrayList();
        for (String subWord : inWord1NotInWord2.toString().split("_s_")) {
            if (!"".equals(subWord.trim())) {
                subWords.add(subWord.trim());
            }

        }
        return subWords;
    }

    /**
     * 只缺少一个阴性词
     *
     * @param word_1 词1
     * @param word_2 词2
     * @return 冲突则ture，否则false
     */
    private boolean onlyLackOfNegativeWord(String word_1, String word_2) {

        List<String> subWords_1 = subWordsInWord1NotInWord2(word_1, word_2);
        List<String> subWords_2 = subWordsInWord1NotInWord2(word_2, word_1);
        if (subWords_1.size() == 1 && subWords_2.size() == 0) {
            return negativeWords.contains(subWords_1.get(0));
        }
        if (subWords_2.size() == 1 && subWords_1.size() == 0) {
            return negativeWords.contains(subWords_2.get(0));
        }

        return false;
    }

    /**
     * 不同的只有冲突词
     *
     * @param word_1 词1
     * @param word_2 词2
     * @return 冲突则ture，否则false
     */
    private boolean onlyDifferentWithConflictWords(String word_1, String word_2) {

        List<String> subWords_1 = subWordsInWord1NotInWord2(word_1, word_2);
        List<String> subWords_2 = subWordsInWord1NotInWord2(word_2, word_1);
        if (subWords_1.size() == 1 && subWords_2.size() == 1) {
            return conflictWordPairMap.getOrDefault(subWords_1.get(0), "").equals(subWords_2.get(0)) ||
                    conflictWordPairMap.getOrDefault(subWords_2.get(0), "").equals(subWords_1.get(0));

        }
        return false;
    }

    /**
     * 是否冲突
     *
     * @param entityBlock_1 实体块1
     * @param entityBlock_2 实体块2
     * @return 冲突true，否则false
     */
    public boolean isConflict(EntityBlock entityBlock_1, EntityBlock entityBlock_2) {

        StringBuilder word1Builder = new StringBuilder();
        entityBlock_1.getEntityWords().forEach(word1Builder::append);
        String word_1 = word1Builder.toString();

        StringBuilder word2Builder = new StringBuilder();
        entityBlock_2.getEntityWords().forEach(word2Builder::append);
        String word_2 = word2Builder.toString();

        if (word_1.length() == 0 || word_2.length() == 0) {
            return false;
        }

        return onlyLackOfNegativeWord(word_1, word_2) || onlyDifferentWithConflictWords(word_1, word_2);
    }

    /**
     * 获取位置
     *
     * @param entityBlock_1 实体块1
     * @param entityBlock_2 实体块2
     * @return List<int [ ]> 对
     */
    public Object[] getPositions(EntityBlock entityBlock_1, EntityBlock entityBlock_2) {
        return new Object[] { entityBlock_1.getPositions(), entityBlock_2.getPositions() };
    }


    /**
     * 找出冲突的位置
     *
     * @param checkPairs   专科检查实体和关系列表
     * @param presentPairs 现病史实体和关系列表
     * @return 冲突位置组对列表
     */
    public List<Object[]> findConflictPositions(Object[] checkPairs, Object[] presentPairs) {
        List<Lemma> checkLemmas = (List<Lemma>) checkPairs[0];
        List<Relation> checkRelations = (List<Relation>) checkPairs[1];

        List<Lemma> presentLemmas = (List<Lemma>) presentPairs[0];
        List<Relation> presentRelations = (List<Relation>) presentPairs[1];

        InvertedIndexTableBuilder checkInvertedIndexTableBuilder = new InvertedIndexTableBuilder(checkLemmas, checkRelations);
        InvertedIndexTableBuilder presentInvertedIndexTableBuilder = new InvertedIndexTableBuilder(presentLemmas, presentRelations);
        Map<String, Set<EntityBlock>> checkInvertedIndexTable = checkInvertedIndexTableBuilder.generateInvertedIndexTablePipeline();
        Map<String, Set<EntityBlock>> presentInvertedIndexTable = presentInvertedIndexTableBuilder.generateInvertedIndexTablePipeline();

        List<EntityBlock[]> entityBlockPairs = match(checkInvertedIndexTable, presentInvertedIndexTable);

        List<Object[]> conflictPositions = Lists.newArrayList();
        entityBlockPairs.forEach(entityBlockPair -> {
            EntityBlock entityBlock_1 = entityBlockPair[0];
            EntityBlock entityBlock_2 = entityBlockPair[1];
            boolean conflict = isConflict(entityBlock_1, entityBlock_2);
            // TODO: 删除调
            //System.out.println("" + conflict + ":" + entityBlock_1 + " ---> " + entityBlock_2);
            if (conflict) {
                conflictPositions.add(getPositions(entityBlock_1, entityBlock_2));
                conflictPositions.add(new Object[]{entityBlock_1,entityBlock_2});
            }
        });
        return conflictPositions;
    }
}
