package com.ch.jedge.jbot.knbase.pool;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ch.jedge.jbot.agent.JedgeGdeSession;
import com.ch.jedge.jbot.knbase.JedgeGptApp;
import com.ch.jedge.jbot.knbase.JedgeGptDomain;
import com.ch.jedge.jbot.knbase.domain.JedgeGdeDomainBlock;
import com.ch.jedge.jbot.knbase.intent.JedgeGdeQuery;
import com.changhong.jedge.JMgbusUtil;
import com.changhong.qlib.QData;
import com.changhong.qlib.intf.QIData;
import com.changhong.qlib.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

import static com.ch.jedge.jbot.agent.JedgeGdeConsts.ival_max_hotLevel_val;
import static com.ch.jedge.jbot.JEJBotLLMConst.*;


public class JedgeGdeKnItemPool {
    private final JedgeGptApp mGdeApp; // 应用主题, 如检测中心,检测较准中心,启睿科检测较准中心
    // private final JedgeContextKnItem nullItem = new JedgeContextKnItem(null, "");

    private final Map<String, JedgeContextKnItem> mKeyPool = new HashMap<>();   //从关键字池，记录每个关键字的热度等参数。

    public JedgeGdeKnItemPool(JedgeGptApp app, JedgeGdeSession session) {
        this.mGdeApp = app;
    }

    //获取当前缓存下、关键字的最热知识。
    public String getActiveContent(JedgeGdeQuery query) {
        /**
         *  通过关键字的组合，检索到相关性最高的知识进行匹配
         *
         *  TODO::
         */
        Map<String, JedgeGdeDomainBlock> added = new HashMap<>();
        StringBuilder tmpResult = new StringBuilder();
        boolean stillEmpty = true;
        synchronized (mKeyPool) {
            if(JedgeGptApp.isDebugMode()) {
                StringBuilder log = new StringBuilder();
                for(Map.Entry<String, JedgeContextKnItem> entry : mKeyPool.entrySet()) {
                    log.append(String.format("%s(%d),", entry.getKey(), entry.getValue().hotLevel));
                }
                mGdeApp.getMgModule().exMarkLog(String.format("Active Key Pool : %s", log));
            }
            //根据对话的关键字检索内容
            for(String qk : query.sel_words_) {
                JedgeContextKnItem item = mKeyPool.get(qk);
                if(item!=null && item.mContent!=null) {
                    if(!added.containsKey(item.mContent.vectorIndex)) {
                        tmpResult.append(item.mContent.blockContent);
                        stillEmpty = false;
                        added.put(item.mContent.vectorIndex, item.mContent);
                    }
                }
            }

            //根据缓存中的关键字检索内容， 如何得到与当前对话最相关的内容？
            if(stillEmpty) {
                for (JedgeContextKnItem item : mKeyPool.values()) { //避免添加重复内容
                    if (item.mContent != null) {
                        if (!added.containsKey(item.mContent.vectorIndex)) {
                            tmpResult.append(item.mContent.blockContent);
                            added.put(item.mContent.vectorIndex, item.mContent);
                        }
                    }
                }
            }
        }
        return tmpResult.toString();
    }

    public void onKnItemHeartbeat() {
        List<String> toDel = new ArrayList<>();
        synchronized (mKeyPool) {
            Set<String> keys = mKeyPool.keySet();
            for(String k : keys) {
                JedgeContextKnItem knItem = mKeyPool.get(k);
                if(knItem.hotLevel<0) continue;
                knItem.hotLevel--;
                if(knItem.hotLevel < 1) {
                    if(JedgeGptApp.isDebugMode()) {
                        mGdeApp.getMgModule().highLog(String.format("Hot key word removed : %s", k));
                    }
                    toDel.add(k);
                }
            }
            if(!toDel.isEmpty()) {
                for (String del : toDel)
                    mKeyPool.remove(del);
                if(JedgeGptApp.isDebugMode())
                    mGdeApp.getMgModule().highLog(String.format("Left : %s", StringUtils.ListToString(mKeyPool.keySet(), ',')));
            }
        }
    }

    public void refreshKeyWord(String key) {
        synchronized (mKeyPool) {
            JedgeContextKnItem item = mKeyPool.get(key);
            item.hotLevel = ival_max_hotLevel_val;
        }
    }

    //如果命中多条知识，如何处理？
    public static final class JedgeContextKnItem {
        public int hotLevel = ival_max_hotLevel_val;
        public float findMatch = 0.9f;
        public String domain = "";    //上次检索的领域
        public JedgeGdeDomainBlock mContent;

        public JedgeContextKnItem(JedgeGdeDomainBlock knItem, String domainName) {
            this.mContent = knItem;
            this.domain = domainName;
        }

        public boolean isValid() {
            return mContent!=null;
        }
    }

    public boolean existsWord(JedgeGptDomain activeDomain, String word) {
        synchronized (mKeyPool) {
            JedgeContextKnItem content = mKeyPool.get(word);
            return content!=null && content.domain.equals(activeDomain.getDomainName());
        }
    }

    //从当前的domain中，提取、并插入关联的知识领域。
    // 当前的关键字， 都需要和对应的 domain 主题进行组合，检索对应的知识信息
    public void pushKeyWord(JedgeGptDomain activeDomain, String word, int lifeTime) {
        //先从本地Hash查找与当前关键字相关的知识block
        JedgeGdeDomainBlock knItem = activeDomain.getKnItemId(word);
        if(knItem!=null) {
            synchronized (mKeyPool) {
                JedgeContextKnItem item = new JedgeContextKnItem(knItem, activeDomain.getDomainName());
                if(lifeTime>0)
                    item.hotLevel = lifeTime;
                mKeyPool.put(word, item);    //刚进入,热度100
            }
            return;
        }


        /**
         *  通过组合多种关键字查早
         *  TODO::组合关键字的方法?去查找?
         */
        JedgeContextKnItem item = new JedgeContextKnItem(null, activeDomain.getDomainName());
//        if(lifeTime<0) {    //非固化关键字
//            JSONArray vecArr = getVectorOfString(word);
//            if(vecArr!=null && !vecArr.isEmpty()) {
//                getKnowledgeFromMilvus(activeDomain, item, vecArr);
//            }
//        }
        //添加新的内容缓存
        synchronized (mKeyPool) {
            mKeyPool.put(word, item);    //刚进入,热度100
        }
        if(JedgeGptApp.isDebugMode())
            mGdeApp.getMgModule().highLog(String.format("Hot key word (%s) pushed : %s", word, item.mContent==null?"null":item.mContent.getBlockInfo()));
    }

    private JSONArray getVectorOfString(String prompt) {
        //发起本地embedding的请求
        QIData r = new QData();
        r.putString("text", prompt);
        int vecSize = mGdeApp.getVectorSize();
        if(vecSize>0)
            r.putInteger("size", vecSize);
        QIData p = mGdeApp.getBotService().postServiceRequest(sval_module_llm,"/glm6b/embedding", r);
        if(JMgbusUtil.isMgbusResultOk(p)) {
            return p.getJsonArray("embedding");
        }
        return null;
    }

    private void getKnowledgeFromMilvus(JedgeGptDomain activeDomain, JedgeContextKnItem context, JSONArray vec) {
        QIData rr = new QData();
        rr.put("v", vec);
        context.domain = (activeDomain == null)? default_vs_domain_ :activeDomain.getDomainName();
        rr.putString("r", context.domain);
        rr.putString("n", mGdeApp.getAppName());
        rr.putInteger("qn", 1); //context.maxReturnItem);  //检索填充itemPool时，追求精确命中。 命中关键字的条数为1。
        rr.put("t", context.findMatch);      //需要动态调整命中精度?

        QIData p = mGdeApp.getBotService().postServiceRequest(sval_modual_vec_db, "/gv/query", rr);
        if(JMgbusUtil.isMgbusResultOk(p)) {
            makeContextFromMilvusResult(context, p);
        }  else if(p.getInteger("code")!=404) {
            mGdeApp.getMgModule().warnLog(String.format("Fail to request to vdb module ： %s", p.toJSONString()));
        }
    }

    private void makeContextFromMilvusResult(JedgeContextKnItem context, QIData p) {
        //结果拼装策略，拼装基于特定关键字检索到的内容
        char cn = 0; double last = 0.0;
        JSONArray arr = p.getJsonArray("payload");
        if(arr ==null || arr.isEmpty()) return;
        StringBuilder result= new StringBuilder();
        for(Object kn : arr) {
            if(kn instanceof JSONObject && !((JSONObject) kn).isEmpty()) {
                mGdeApp.getMgModule().infoLog(String.format("Checking result : %s", ((JSONObject) kn).toJSONString()));
                if(!((JSONObject) kn).containsKey("s") || !((JSONObject) kn).containsKey("vi")) continue;
                //策略: 高度相似,只取一个
                Object v = ((JSONObject) kn).get("s");
                if( ! (v instanceof BigDecimal))
                    continue;
                double d =  ((BigDecimal) v).doubleValue();
                if( d > 0.86 && last>0.1 &&
                        (last - d >0.3 || cn > 2 )) {
                    break;
                }
                Object ao = ((JSONObject) kn).get("a");
                Object vi = ((JSONObject) kn).get("vi");
                if(! (ao instanceof String) || !(vi instanceof BigDecimal))
                    continue;
                String a = (String) ao;
                result.append(a);
                long lVi = ((BigDecimal)vi).longValue();

                //插入和检索的格式需要发生变化:

                // TODO:: 从知识库中获取blockIndex信息
//
//                context.mContent.vectorIndex = String.valueOf(lVi);
//                context.content =  result.toString();

                if(d>0.9) {    //高度相似，只取一个答案
                    break;
                }
                cn++;
                last = d;
            }
        }
    }

}
