package com.ch.jedge.jbot.knbase;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ch.jedge.jbot.JedgeBotGptService;
import com.ch.jedge.jbot.JedgeLlmUtil;
import com.ch.jedge.jbot.agent.JedgeGdeSession;
import com.ch.jedge.jbot.dict.JEDictUtil;
import com.ch.jedge.jbot.dict.JedgeWordDict;
import com.ch.jedge.jbot.knbase.domain.JedgeGdeDomainParer;
import com.ch.jedge.jbot.knbase.intent.JedgeGdeQuery;
import com.ch.jedge.jbot.session.JedgeServiceSession;
import com.ch.jedge.utils.JEVdbConfigUtil;
import com.changhong.jedge.JMgbusModual;
import com.changhong.qlib.util.StringUtils;
import com.changhong.qlib.util.file.FileUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ch.jedge.jbot.agent.JedgeGdeConsts.ival_default_vector_size;
import static com.ch.jedge.jbot.agent.JedgeGdeConsts.sval_default_domain;

public class JedgeGptApp {
    private static final boolean _debugActive = JEVdbConfigUtil.getConfigBoolean("vdb", "debug", false);
    private static final boolean _gptHistoryEnabled = JEVdbConfigUtil.getConfigBoolean("vdb", "history", false);;
    private static final int _vectorSize = JEVdbConfigUtil.getConfigInteger("vdb", "vectorSize", ival_default_vector_size);

    protected final Map<String, JedgeGptDomain> domains_ = new HashMap<>();
    private final String mAppName;
    private final String mAppPath;
    private final JMgbusModual mgModule;
    private final JedgeBotGptService mgService;
    private final JedgeWordDict commonDict;
    private final JedgeWordDict VdbKeyDict;     //关键字词库
    private static final String sval_common_dict_fn = "common.dic";
    private static final String sval_db_key_dict_fn = "vdb_vocab.dic";
    private String homeDomain = sval_default_domain;

    public JedgeGptApp(JMgbusModual module, JedgeBotGptService service, String appPath) {
        this.mgModule = module;
        this.mgService = service;
        this.mAppName = StringUtils.getSubStrAfter(appPath,File.separatorChar, -1);
        this.mAppPath = appPath;

        String commonDictFile = FileUtils.contactPath(appPath, sval_common_dict_fn);
        this.commonDict = JEDictUtil.loadStaticCommonDict(appPath, new File(commonDictFile));
        String vdbDicFile = FileUtils.contactPath(appPath, sval_db_key_dict_fn);
        this.VdbKeyDict = JEDictUtil.loadStaticCommonDict(appPath, new File(vdbDicFile));
    }

    public boolean loadDomains() {
        List<File> files = FileUtils.findFileWithExtInDir(mAppPath, "dm", 0);
        for(File f : files) {
            loadGdeDomain(f.getAbsolutePath());
        }

        synchronized (domains_) {
            if(!domains_.containsKey(homeDomain))
                homeDomain = JedgeLlmUtil.getFirstRandomKey(domains_.keySet());
        }

        return isValidApp();
    }

    private boolean isValidApp() {
        return true;
    }

    private void loadGdeDomain(String domainFilename) {
        JedgeGdeDomainParer parser = new JedgeGdeDomainParer(this, domainFilename);
        JedgeGptDomain gdeDomain = parser.parseGdeDomain();
        if(gdeDomain!=null && gdeDomain.isValid()) {
            synchronized (domains_) {
                domains_.put(gdeDomain.getDomainName(), gdeDomain);
            }
        } else { //加载报错
            mgModule.errLog(String.format("[ERR!!]Fail to load Gde domain : %s", domainFilename));
        }
    }

    public String getAppName() {
        return mAppName;
    }

    /**
     *  处理用户对话的过程：
     *      可能涉及到的对外部的复杂调用：
     *      （1） 分词
     *      （2） 分类判断（判断上下文相关性、判断领域、判断意图等）
     *      （3） 从上下文中提取参数
     *      （4） 意图执行（调用预置API，或其它工作）
     */
    public boolean handleQuery(JedgeServiceSession s, String query) {

        JedgeGdeSession gdeSession = s.getGdtSession();
        //基于上下文,判断当前query与主题的相容性（是否是一个新的对话话题）
        if(_debugActive) {
            gdeSession.returnGptResponseMessage(String.format("[%s(%d)]>>", mAppName, s.sid));
            gdeSession.returnGptResponseMessage("[来自GDE的接管应答]");
        }

        //用户的请求入栈：响应机器人提取对话数据进行处理。
        gdeSession.pushQuery(query);

        return true;
    }

    public static boolean isHistoryEnabled() {
        return _gptHistoryEnabled;
    }

    public void setInitDomain(JedgeGdeSession session) {
        //初始化
        synchronized (domains_) {
            for(JedgeGptDomain a : domains_.values()) {
                session.loadDomainGateWord(a);
                // SystemUtils.tryWait(200);
            }
        }
        session.switchActiveDomain(homeDomain);
        //向Session中加载所有可用的  Domain 的切换关键字
    }

    public JMgbusModual getMgModule() {
        return mgModule;
    }

    public JedgeBotGptService getBotService() {
        return mgService;
    }

    public JedgeGptDomain getDomainByName(String homeDomain) {
        synchronized (domains_) {
            return domains_.get(homeDomain);
        }
    }

    public int getVectorSize() {
        return _vectorSize;
    }

    public static boolean isDebugMode() {
        return _debugActive;
    }

    public void onHeartBeat() {
        //TODO::卸载不用的 Domain 信息
    }

    public String getHomeDomainKey() {
        return homeDomain;
    }

    public void activeCommonWords() {
        getBotService().activeWordDict(commonDict);
    }

    /**
     * paddle模式词性和专名类别标签集合如下表，其中词性标签 24 个（小写字母），专名类别标签 4 个（大写字母）。
     *
     * | 标签 | 含义     | 标签 | 含义     | 标签 | 含义     | 标签 | 含义     |
     * | ---- | -------- | ---- | -------- | ---- | -------- | ---- | -------- |
     * | n    | 普通名词 | f    | 方位名词 | s    | 处所名词 | t    | 时间     |
     * | nr   | 人名     | ns   | 地名     | nt   | 机构名   | nw   | 作品名   |
     * | nz   | 其他专名 | v    | 普通动词 | vd   | 动副词   | vn   | 名动词   |
     * | a    | 形容词   | ad   | 副形词   | an   | 名形词   | d    | 副词     |
     * | m    | 数量词   | q    | 量词     | r    | 代词     | p    | 介词     |
     * | c    | 连词     | u    | 助词     | xc   | 其他虚词 | w    | 标点符号 |
     * | PER  | 人名     | LOC  | 地名     | ORG  | 机构名   | TIME | 时间     |
     * @param query 源词汇
     */

    public JSONArray cutWords(String query) {
        return getBotService().cutWords(query);
    }

    private JSONArray getSubWords(JSONArray words, int i, int n, int maxLen) {
        JSONArray sub = new JSONArray();
        for(int j=i;j<n+i && j<maxLen;j++) {
            sub.add(words.get(j));
        }
        return sub;
    }

    //检查短语的合法性（在意图或领域中，标记一些使用频度较高的短语类型）
    private JSONObject checkTerms(JSONArray terms) {
        //如何检查subwords是否合理?
        StringBuilder checkWord = new StringBuilder();
        for(Object word : terms) {
            String w = ((JSONObject) word).getString("w");
            checkWord.append(w);
            String t = ((JSONObject) word).getString("t");
        }

        //TODO::根据词性或关键字进行比对。
        //所谓的特征词库，实际上时一个概念集的最基础定义。   元定义 + 关联性及其动作，够成了含义。
        JSONObject obj = new JSONObject();

        //组合词和词性，去匹配当前领域下的各意图的短语集合
//        mgModule.highLog(String.format("Checking terms : %s", checkWord));

        return null;
    }


    public void scanTerms(JedgeGdeQuery intent) {
        if(intent!=null && intent.words_!=null && !intent.words_.isEmpty()) {
            //识别标点符号后断句，
            //记录每个句子的start和end
            List<Integer> symbols = new ArrayList<>();
            List<JSONObject> terms = new ArrayList<>();
            int idx = 0;
            for(Object word : intent.words_) {
                String t = ((JSONObject) word).getString("t");
                if("x".equals(t)) {
                    symbols.add(idx);
                }
                idx++;
            }

            int maxLen = intent.words_.size();
            if(symbols.isEmpty() || maxLen>=idx) symbols.add(maxLen);

            //断句后开始下一步
            int end = -1;
            for(Integer dot : symbols) {
                int start = end+1;
                end = dot;
                //1、优先匹配长度更长的短语
                //2、出现歧义时，如何回退

                for(int n=end-start;n>=2;n--) {
                    for(int i=end-n;i>=start;i--) {
                        //index i 开始的第 n 个词汇
                        JSONArray subWords = getSubWords(intent.words_, i, n, maxLen);
                        //检查subWords是否符合一般性语法,如果是,则作为一个有含义的短语入栈
                        //提取主关键字，去匹配可能的有含义的词  <刘德华>拍的<电影> (是一种合法的语法)
                        JSONObject r = checkTerms(subWords);
                        if(r!=null) {
                            //命中了短语，记录这个短语的开始位置和长度
                            r.put("s", i);
                            r.put("l", n);
                            terms.add(r);
                        }
                    }
                }

                //从大到小，按照不重叠的方式，组合这些短语，优先匹配长的短语
                if(!terms.isEmpty()) {//匹配到有效短语
                    intent.rebuildWords(start, end, terms);
                } else {
                    intent.rebuildWords(start, end, symbols.size()>1);
                }
            }
        }
    }

}
