package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.analysis.domain.DADimension;
import cn.ibizlab.core.extensions.domain.BaseRequest;
import cn.ibizlab.core.extensions.domain.SqlResultsMQMsg;
import cn.ibizlab.core.extensions.util.ExpiryMap;
import cn.ibizlab.core.extensions.util.LocalMsgResultProducerService;
import cn.ibizlab.core.lite.extensions.domain.FieldObj;
import cn.ibizlab.core.lite.extensions.domain.ModelObj;
import cn.ibizlab.core.rule.domain.ExecLog;
import cn.ibizlab.core.rule.domain.ExecResult;
import cn.ibizlab.core.rule.service.IExecLogService;
import cn.ibizlab.util.dict.CodeItem;
import cn.ibizlab.util.dict.CodeList;
import cn.ibizlab.util.helper.CachedBeanCopier;
import cn.ibizlab.util.helper.DataObject;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

/**
 * cassandra数据库和mysql等关系数据库
 * 报表数据构建结果分析处理
 */
@Slf4j
@Service("AnalyseEntityServiceImpl")
@ConditionalOnExpression("'all'.equals('${ibiz.analyseMode:}')")
public class AnalyseAllServiceImpl extends BaseEntityServiceImpl {

    @Autowired
    @Lazy
    protected IExecLogService ruExecLogService;
    @Autowired
    @Lazy
    private LocalMsgResultProducerService localMsgResultProducerService;
    @Autowired
    @Lazy
    private DABuildExService daBuildExService;
    @Value("${cassandra.host:}")
    private String cassandraHost;
    @Value("${ibiz.resultsBatchSend:true}")
    protected boolean resultsBatchSend;


    private ExpiryMap<String,List<DADimension>> dimlistMap = new ExpiryMap<>();

    @Override
    public void saveResult(ModelObj param, String RULEID,String RULECODE, String RULENAME, String RU_EXECRESULTNAME, FieldObj BUSINESSCAT,
                           Integer RETVALUE, FieldObj KEYVALUEFIELD, FieldObj DOMAINSFIELD,FieldObj DIMFIELD,
                           FieldObj METRICFIELD, FieldObj TIMEFIELD, FieldObj EXT1FIELD, FieldObj EXT2FIELD)
    {
        if (!StringUtils.isEmpty(cassandraHost) && 0 == RETVALUE){
            // 使用cassandra数据库时且业务数据不满足当前规则时返回，cassandra数据库删除结果数据，依赖业务数据主键和规则集合
            return;
        }
        ExecResult result = new ExecResult();
        result.setRuleId(RULEID);
        result.setRuleName(RULENAME);
        result.setName(RU_EXECRESULTNAME);
        result.setRetValue(RETVALUE);
        if(DOMAINSFIELD == null){
            DOMAINSFIELD = param.getEmpty();
        }
        if(BUSINESSCAT == null){
            BUSINESSCAT = param.getEmpty();
        }
        if(METRICFIELD == null){
            METRICFIELD = param.getEmpty();
        }
        if(TIMEFIELD == null){
            TIMEFIELD = param.getEmpty();
        }
        if(EXT1FIELD == null){
            EXT1FIELD = param.getEmpty();
        }
        if(EXT2FIELD == null){
            EXT2FIELD = param.getEmpty();
        }
        result.setKeyValueField(param.getRowKey());
        result.setBusinessCat(BUSINESSCAT.getValue(String.class,null));
        result.setMetricField(METRICFIELD.getDecimal());
        Timestamp timefield = TIMEFIELD.getValue(Timestamp.class,null);
        if(timefield != null) {
            result.setTimeField(timefield);
        }
        String ext1 = EXT1FIELD.getValues();
        if(ext1.length()> 330){
            ext1 = ext1.substring(0,330)+"...";
        }
        if(!StringUtils.isEmpty(ext1)){
            result.setExt1Field(ext1);
        }
        String ext2 = EXT2FIELD.getValues();
        if(ext2.length()> 330){
            ext2 = ext2.substring(0,330)+"...";
        }
        if(!StringUtils.isEmpty(ext2)){
            result.setExt2Field(ext2);
        }
        result.setDomainsField(DOMAINSFIELD.getValue(String.class, ""));
        result.setSystemId(DataObject.getStringValue(param.get("systemid"),null));
        if((!StringUtils.isEmpty(result.getRuleId()))&&(!StringUtils.isEmpty(result.getKeyValueField()))) {
            List<DADimension> dims = getDims(result.getBusinessCat());
            if(dims!=null) {
                for (DADimension dim : dims) {
                    String codevalue = param.$(dim.getField()).getValue(String.class,"");
                    if(!StringUtils.isEmpty(codevalue)) {
                        String dictname = dim.getDict();
                        Object val = codevalue;
                        if(!StringUtils.isEmpty(dictname)) {
                            CodeList codeList = this.getCodeListCatalog(dictname);
                            //维度指定代码表时，向上同时为每一个父节点添加一条数据
                            while(true) {
                                CodeItem code = codeList.findCodeItem(val);
                                if(code != null) {
                                    ExecResult result2 = new ExecResult();
                                    CachedBeanCopier.copy(result, result2);
                                    result2.setDimField(code.getValue().toString());
                                    result2.setId(result2.getDefaultKey(true).toString());
                                    if(result2.getRetValue() == 1) {
                                        addResults(param,result2);
                                    }else {
                                        deleteResults(param,result2.getId());
                                    }
                                    //非逐层核算或无父代码项退出
                                    if(dim.getRecursive() == 0 || StringUtils.isEmpty(code.getParent())) {
                                        break;
                                    }else{
                                        val = code.getParent();
                                    }
                                }else {
                                    break;
                                }
                            }
                        }else{
                            //维度未指定代码表时，只保存一条数据
                            result.setDimField(codevalue);
                            ExecResult result2 = new ExecResult();
                            CachedBeanCopier.copy(result, result2);
                            result2.setId(result2.getDefaultKey(true).toString());
                            if(result2.getRetValue() == 1) {
                                addResults(param,result2);
                            }else {
                                deleteResults(param,result2.getId());
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 添加到新增结果队列
     * @param param
     * @param result
     */
    protected void addResults(ModelObj param, ExecResult result){
        List<ExecResult> results;
        if(param.containsKey(Tag_SaveResults)){
            results = (List<ExecResult>)param.get(Tag_SaveResults);
        }else{
            results = new ArrayList<>();
            param.set(Tag_SaveResults, results);
        }
        results.add(result);
    }

    /**
     * 添加到删除结果队列
     * @param param
     * @param ru_execresultid
     */
    protected void deleteResults(ModelObj param, String ru_execresultid){
        List<String> results;
        if(param.containsKey(Tag_DeleteResults)){
            results = (List<String>)param.get(Tag_DeleteResults);
        }else{
            results = new ArrayList<>();
            param.set(Tag_DeleteResults, results);
        }
        results.add(ru_execresultid);
    }

    /**
     * 获取维度集合
     * @param id
     * @return
     */
    public List<DADimension> getDims(String id) {
        List<DADimension> dims = dimlistMap.get("dims" + id);
        if(dims == null){
            dims = daBuildExService.get(id).getDadimension();
            if(dims != null) {
                dimlistMap.put("dims" + id, dims);
            }
        }
        return dims;
    }

    @Override
    public ExecLog processAll(BaseRequest msg) {
        ExecLog execlog=new ExecLog();
        execlog.setId(msg.getId());
        execlog.setRunBody(msg.toString());
        StringBuilder strErrorInfo=new StringBuilder();
        int count = 0;
        int errorcount = 0;
        String strResId=initRule(msg.getRules(),msg.getBatch());
        if (StringUtils.isEmpty(strResId)) {
            strErrorInfo.append("准备rule文件错误");
            strErrorInfo.append("\r\n");
            execlog.setRetCode(2);
            execlog.setCnt(count);
            execlog.setSucc(errorcount);
            execlog.setRunResult(strErrorInfo.toString());
            ruExecLogService.update(execlog);
            return execlog;
        }

        List<SqlResultsMQMsg> sqlResultsMQMsgList = new ArrayList<>();
        try {
            for (ModelObj modelObj : msg.getDatas()){
                try{
                    count++;
                    modelObj.set("BATCH",msg.getBatch());
                    modelObj.set(Tag_EngineId, msg.getEngineId());
                    modelObj.set("systemid",msg.getSystemid());
                    if(!StringUtils.isEmpty(msg.getResultDataSource())){
                        modelObj.set("resultDataSource", msg.getResultDataSource());
                    }
                    if(!StringUtils.isEmpty(msg.getResultTableName())){
                        modelObj.set("resultTableName", msg.getResultTableName());
                    }
                    processRule(modelObj, modelObj.getRowKey(),strResId);
                    //构建结果消息对象
                    SqlResultsMQMsg resultsMQMsg = new SqlResultsMQMsg();
                    resultsMQMsg.setMsgId(msg.getId());
                    resultsMQMsg.setKeyValueField(modelObj.getRowKey());
                    resultsMQMsg.setRules(msg.getRuleIds());
                    Object saveResults = modelObj.get(Tag_SaveResults);
                    if(saveResults != null && saveResults instanceof List){
                        resultsMQMsg.setSaveDatas((List<ExecResult>)saveResults);
                    }
                    if (StringUtils.isEmpty(cassandraHost)){
                        resultsMQMsg.setResultDataSource(msg.getResultDataSource());
                        resultsMQMsg.setResultTableName(msg.getResultTableName());
                        // 不存储至cassandra时，删除主键集合添加（cassandra删除数据不依靠规则结果数据主键）
                        Object deleteResults = modelObj.get(Tag_DeleteResults);
                        if(deleteResults != null && deleteResults instanceof List){
                            resultsMQMsg.setDeleteIds((List<String>)deleteResults);
                        }
                    }
                    if (resultsBatchSend){
                       sqlResultsMQMsgList.add(resultsMQMsg);
                    }else {
                        localMsgResultProducerService.sendBuildResultsMsg(resultsMQMsg);
                    }
                } catch (Exception e) {
                    errorcount++;
                    log.error("Service错误，加载数据详细信息：" + modelObj.getRowKey() + "," + e.getMessage());
                    if (strErrorInfo.toString().length() <= 5000) {
                        strErrorInfo.append("加载数据详细信息：" + modelObj.getRowKey() + ",错误：" + e.getMessage());
                        strErrorInfo.append("\r\n");
                        if (e.getCause() != null && e.getCause().getMessage() != null) {
                            strErrorInfo.append(e.getCause().getMessage());
                            strErrorInfo.append("\r\n");
                        }
                    }
                }
            }
            if (resultsBatchSend && sqlResultsMQMsgList.size() > 0){
                localMsgResultProducerService.sendBuildResultsMsgList(sqlResultsMQMsgList);
            }
        }catch(Exception e) {
            log.error("Service读取BaseRequest错误:" + e.toString());
            strErrorInfo.append("读取BaseRequest错误:" + e.getMessage());
            strErrorInfo.append("\r\n");
            if (e.getCause() != null && e.getCause().getMessage() != null) {
                strErrorInfo.append(e.getCause().getMessage());
                strErrorInfo.append("\r\n");
            }
            execlog.setRetCode(1);
            execlog.setCnt(count);
            if (errorcount == 0) {
                execlog.setSucc(0);
            }else {
                execlog.setSucc(count - errorcount);
            }
            execlog.setRunResult(strErrorInfo.toString());
            ruExecLogService.update(execlog);
            return execlog;
        }finally{
            sqlResultsMQMsgList.clear();
            if(setkieSession.containsKey(strResId)){
                KieSession kieSession = setkieSession.get(strResId);
                try{
                    kieSession.dispose();
                } catch (Exception ex){}
                setkieSession.remove(strResId);
                setRuleCount.remove(strResId);
            }
        }
        log.info(new StringBuilder().append("Service成功，process successfully:").append(msg.toString()).toString());
        strErrorInfo.append("Service成功，process successfully\r\n");
        execlog.setCnt(count);
        execlog.setSucc(count-errorcount);
        if(execlog.getCnt() == 0) {
            execlog.setRetCode(3);
        }else{
            execlog.setRetCode(0);
        }
        execlog.setRunResult(strErrorInfo.toString());
        this.ruExecLogService.update(execlog);
        return execlog;
    }

}
