package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.extensions.util.FreeMakerHelper;
import cn.ibizlab.core.lite.extensions.model.DataModel;
import cn.ibizlab.core.lite.extensions.service.LiteModelService;
import cn.ibizlab.core.lite.extensions.util.LiteStorage;
import cn.ibizlab.core.rule.service.impl.RuleItemServiceImpl;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import cn.ibizlab.core.rule.domain.RuleItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.context.annotation.Primary;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.io.File;
import java.util.*;

/**
 * 实体[规则] 自定义服务对象
 */
@Slf4j
@Primary
@Service("RuleItemExService")
public class RuleItemExService extends RuleItemServiceImpl {

    @Value("${ibiz.rulepath:/app/file/rules/}")
    String rulePath;
    private Object lockModel=new Object();

    @Override
    public boolean create(RuleItem et) {
        buildRuleFile(et);
        return super.create(et);
    }

    @Override
    public boolean update(RuleItem et) {
        buildRuleFile(et);
        return super.update(et);
    }

    @Override
    protected Class currentModelClass() {
        return com.baomidou.mybatisplus.core.toolkit.ReflectionKit.getSuperClassGenericType(this.getClass().getSuperclass(), 1);
    }

    /**
     * [Modelchange:modelchange] 行为扩展
     * @param et
     * @return
     */
    @Override
    @Transactional
    public RuleItem modelchange(RuleItem et) {
        if((!StringUtils.isEmpty(et.getModelId())) && (et.getModelId().equalsIgnoreCase("4dfba2a475c4fb83cd50b9d316f3e7b6")||et.getModelId().equalsIgnoreCase("4dfba2a475c4fb83cd50b9d316f3e7b6")))
        {
            et.setFieldSet("{\"modelid\":\"a37711c0157cbd8e6ed121de8fc5a118\",\"metricentity\":\"TYYW_GG_AJJBXX\",\"metricfield\":\"TYYW_GG_AJJBXX.BMSAH\",\"timeentity\":\"TYYW_GG_AJJBXX\",\"timefield\":\"TYYW_GG_AJJBXX.SLRQ\",\"domainsentity\":\"TYYW_GG_AJJBXX\",\"domainsfield\":\"TYYW_GG_AJJBXX.CBDW_BM\",\"dimentity\":\"DL_GG_AJBLRY\",\"dimfield\":\"DL_GG_AJBLRY.CBRY\",\"keyvalueentity\":\"TYYW_GG_AJJBXX\",\"keyvaluefield\":\"TYYW_GG_AJJBXX.BMSAH\",\"businesscatentity\":\"DL_GG_AJXX\",\"businesscatfield\":\"DL_GG_AJXX.BZTXBM\",\"ext1entity\":\"\",\"ext1field\":\"\",\"ext2entity\":\"\",\"ext2field\":\"\"}");
        }
        return super.modelchange(et);
    }

    @Autowired
    private LiteModelService liteModelService;

    /**
     * 按照规则生成drl文件
     * @param et
     * @throws Exception
     */
    @Override
    public RuleItem buildRuleFile(RuleItem et){
        try {
            boolean hasBusinesscatField=false;
            //获取实体配置信息
            String strCfg = et.getCfg();
            String strRuleid = et.getRuleId();
            String strRulename = StringUtils.isEmpty(et.getRuleName())?"":et.getRuleName().replace("\\", "");
            String strMemo = StringUtils.isEmpty(et.getMemo())?"":et.getMemo().replace("\\", "");
            String strRuleGroup = et.getGroup();
            String strFieldset=et.getFieldSet();
            String strMetricfield = "",strTimefield= "",strExt1field= "",strKeyvaluefield= "",strExt2field= "",strDomainsfield="" ,strDimfield="" ,strBusinesscatfield="";
            if(StringUtils.isEmpty(strRuleGroup)){
                log.error(String.format("由于[%s-%s]规则尚未选择规则分组，将不予生成drl规则文件~!",strRuleid,strRulename));
                return et;
            }
            if(StringUtils.isEmpty(strCfg)){
                log.error(String.format("由于[%s-%s]规则尚未配置规则，将不予生成drl规则文件~!",strRuleid,strRulename));
                return et;
            }
            JSONObject cfg=JSONObject.parseObject(strCfg);
            JSONArray fieldArray= cfg.getJSONArray("field") , groupArray =cfg.getJSONArray("group") ,releationArray=cfg.getJSONArray("releation");
            if(  (ObjectUtils.isEmpty(fieldArray) || (!ObjectUtils.isEmpty(fieldArray) &&  fieldArray.size()==0 ))  &&
                 (ObjectUtils.isEmpty(groupArray) || (!ObjectUtils.isEmpty(groupArray) &&  groupArray.size()==0 )) &&
                    (ObjectUtils.isEmpty(releationArray) || (!ObjectUtils.isEmpty(releationArray) &&  releationArray.size()==0 ))
              )
            {
                log.error(String.format("由于[%s-%s]规则尚未配置规则，将不予生成drl规则文件~!",strRuleid,strRulename));
                return et;
            }
            //准备模板参数
            JSONObject obj=null;
            if(!StringUtils.isEmpty(strFieldset)){
                obj=JSONObject.parseObject(strFieldset);
                strMetricfield=obj.getString("metricfield");
                strTimefield=obj.getString("timefield");
                strExt1field=obj.getString("ext1field");
                strKeyvaluefield=obj.getString("keyvaluefield");
                strExt2field=obj.getString("ext2field");
                strDimfield=obj.getString("dimfield");
                strBusinesscatfield=obj.getString("businesscatfield");
                strDomainsfield=obj.getString("domainsfield");
            }
            if(StringUtils.isEmpty(strDomainsfield))
                strDomainsfield=strDimfield;

            Map param=new HashMap();
            param.put("ruleid",strRuleid);
            param.put("rulecode",et.getRuleCode());
            param.put("rulename",strRulename);
            param.put("memo",strMemo);

            DataModel dataModel = liteModelService.getDataModel(et.getModelId());

            synchronized(lockModel)
            {
                Hashtable<String,String> modelset=new Hashtable<String,String>();
                param.put("datamodelname",dataModel.getDataModelName());
                modelset.put("datamodelname",dataModel.getDataModelName());
                param.put("rulecond",parseGroup(cfg,modelset));
                param.put("releationcond",parseRelationArr(JSONObject.parseObject(strCfg),modelset));




                boolean b=false;
                for(String key : modelset.keySet()) {
                    if(key.equalsIgnoreCase("datamodelname")||key.startsWith("EXIST")||key.startsWith("NOTEXIST"))
                        continue;
                    b=true;
                    break;
                }
                if(!b)
                {
                    log.error(String.format("由于[%s-%s]规则尚未配置规则，将不予生成drl规则文件~!",strRuleid,strRulename));
                    return et;
                }

                param.put("metricfield",getFieldset(strMetricfield,modelset));
                param.put("timefield",getFieldset(strTimefield,modelset));
                param.put("ext1field",getFieldset(strExt1field,modelset));
                param.put("keyvaluefield",getFieldkeyset(strKeyvaluefield,modelset));
                param.put("ext2field",getFieldset(strExt2field,modelset));
                param.put("domainsfield",getFieldset(strDomainsfield,modelset));
                param.put("dimfield",getFieldset(strDimfield,modelset));
                param.put("dimfield_d",dataModel.getDataModelName()+".$(\""+strDimfield+"\")");
                param.put("keyvaluefield_d",StringUtils.isEmpty(strKeyvaluefield)?dataModel.getDataModelName()+".$K()":dataModel.getDataModelName()+".$(\""+strKeyvaluefield+"\")");
                if (!StringUtils.isEmpty(strBusinesscatfield)) {
                    param.put("businesscatfield", getFieldset(strBusinesscatfield, modelset));
                } else {
                    param.put("businesscatfield", getStaticFieldset(et.getBusinessCat(), modelset));
                }

                LinkedHashSet<String> cond = new LinkedHashSet();
                for(String key : modelset.keySet()) {
                    if(key.equalsIgnoreCase("datamodelname"))
                        continue;
                    if(key.startsWith("EXIST")||key.startsWith("NOTEXIST")) {

                        DataModel sub=dataModel.findDataModel(modelset.get(key),"DOWN");
                        if(sub!=null)
                            cond.add(sub.getFactPorperty().getPropertyName());
                        continue;
                    }
                    cond.add(key);

                }

                et.setCond(JSONArray.toJSONString(cond));

            }

            String[] groupArr=strRuleGroup.split(";");

            //按照规则类别输出drl文件
            for(String ruleGroup:groupArr){

                param.put("rulegroup",ruleGroup);
                String ruleGroupFolderPath=String.format("%s%s/",rulePath,ruleGroup.toUpperCase());
                File outputFileFolder=new File(ruleGroupFolderPath);
                if(!outputFileFolder.exists())
                    outputFileFolder.mkdirs();

                File outputFilePath=new File(String.format("%s/%s.drl",ruleGroupFolderPath,strRuleid));
                FreeMakerHelper.outputFreeMaker("/ftl/","DSTRule.drl.ftl",param,outputFilePath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return et;
    }

    /**
     * 组查询
     * @param groupObj
     * @return
     */
    private String parseGroup(JSONObject groupObj,Hashtable<String,String> modelset){
        if(StringUtils.isEmpty(groupObj))
            return "";

        String conn=groupObj.getString("groupcond").replaceAll("AND","&&").replaceAll("OR","||");  //获取组合方式
        JSONArray fieldArr=groupObj.getJSONArray("field"); //获取值项数组
        String strFieldCond=parseFieldList(fieldArr,conn,modelset); //获取值项表达式

        JSONArray groupArr=groupObj.getJSONArray("group");//获取组合条件
        String strGroupCond="";
        if((!StringUtils.isEmpty(groupArr)) && groupArr.size()>0){
            strGroupCond=parseGroupList(groupArr,conn,modelset);  //获取组合条件表达式
        }
        String strRuleCond=getRuleCond(strFieldCond,strGroupCond,conn);//获取总表达式（值项+组合）
        return strRuleCond;
    }

    /**
     * 获取规则总表达式（值项+组合）
     * @param strFieldCond	值项表达式
     * @param strGroupCond 组合表达式
     * @param conn		   组合方式
     * @return
     */
    private String getRuleCond(String strFieldCond,String strGroupCond,String conn)
    {
        String strRuleCond="";
        if((!StringUtils.isEmpty(strFieldCond) && (!StringUtils.isEmpty(strGroupCond)))){
            strRuleCond=String.format("(%s %s %s)",strFieldCond,conn,strGroupCond);
        }
        else if(!StringUtils.isEmpty(strFieldCond)){
            strRuleCond=String.format("%s",strFieldCond);
        }
        else if(!StringUtils.isEmpty(strGroupCond)){
            strRuleCond=String.format("%s",strGroupCond);
        }
        return strRuleCond;

    }

    /**
     * 组查询
     * @param GroupArr
     * @param conn
     * @return
     */
    private String parseGroupList(JSONArray GroupArr,String conn,Hashtable<String,String> modelset){
        if(StringUtils.isEmpty(GroupArr)||GroupArr.size()==0)
            return "";
        StringBuffer sbf=new StringBuffer();
        for(int a=0;a<GroupArr.size();a++){
            String strGroupCond=parseGroup(GroupArr.getJSONObject(a),modelset);
            sbf.append(strGroupCond);
            if(a!=GroupArr.size()-1)//去掉最后的连接符
                sbf.append(conn+" ");
        }
        return String.format("(%s)",sbf.toString());
    }

    /**
     * @param fieldArr field数组
     * @param conn	field连接符
     * @return
     */
    private String parseFieldList(JSONArray fieldArr,String conn,Hashtable<String,String> modelset){
        if(StringUtils.isEmpty(fieldArr)||fieldArr.size()==0)
            return "";
        StringBuffer sbf=new StringBuffer();
        for(int a=0;a<fieldArr.size();a++){
            JSONObject fieldObj=fieldArr.getJSONObject(a);
            String fieldCond=parseField(fieldObj,modelset);
            sbf.append(fieldCond);
            if(a!=fieldArr.size()-1)//去掉最后的连接符
                sbf.append(conn+" ");
        }
        return String.format("(%s)",sbf.toString());
    }

    /**
     * 拼接field表达式
     * @param fieldObj
     * @return
     */
    private String parseField(JSONObject fieldObj,Hashtable<String,String> modelset){
        String fieldName=fieldObj.getString("fieldname");
        String fieldCond=fieldObj.getString("fieldcond");
        String condValue=fieldObj.getString("condvalue");
        if(modelset!=null)
        {
            String[] arr=fieldName.split("[.]");
            if(arr.length>=2)
            {
                if(!modelset.containsKey(arr[0]))
                {
                    modelset.put(arr[0], modelset.get("datamodelname"));
                }

            }
        }
        return String.format("IF(\"%s %s %s\")",fieldName,fieldCond,condValue);

    }

    /**
     * 解析子逻辑数组
     * @return
     */
    private String parseRelationArr(JSONObject groupObj ,Hashtable<String,String> modelset){
        if(!groupObj.containsKey("releation"))
            return null;
        JSONArray RelationArr=groupObj.getJSONArray("releation");
        if(StringUtils.isEmpty(RelationArr)||RelationArr.size()==0)
            return null;
        StringBuffer sbf=new StringBuffer();
        for(int a=0;a<RelationArr.size();a++){
            String strRelationCond=parseRelation(RelationArr.getJSONObject(a),modelset);
            sbf.append(strRelationCond);
        }
        return sbf.toString();
    }

    /**
     * 解析子数据逻辑
     * @param relationObj
     * @param modelset
     * @return
     */
    private String parseRelation(JSONObject relationObj,Hashtable<String,String> modelset){
        if(StringUtils.isEmpty(relationObj))
            return "";

        String relaConn=relationObj.getString("releationcond");//操作符
        String relaEntity=relationObj.getString("releationentity");//实体
        JSONArray relaGroup=relationObj.getJSONArray("group");//规则数组



        String strGroupCond="";
        if((!StringUtils.isEmpty(relaGroup)) && relaGroup.size()>0){
            strGroupCond=parseGroupList(relaGroup,"&&",modelset);//Relation各组之间用and连接
        }

        String strRelationResult="";
        if(!StringUtils.isEmpty(strGroupCond)){
            if(relaConn.equals("exists"))
            {
                strRelationResult=String.format("%s:ModelObj %s from %s.getNested(\"%s\")",relaEntity,strGroupCond,modelset.get("datamodelname"),relaEntity);
                modelset.put("EXIST",relaEntity);
                modelset.put("EXIST-"+relaEntity,relaEntity);
            }
            else if(relaConn.equals("not exists")){
                modelset.put("NOTEXIST-"+relaEntity,relaEntity);
                strRelationResult=String.format("not(exists ModelObj %s from %s.getNested(\"%s\"))",strGroupCond,modelset.get("datamodelname"),relaEntity);
            }
        }
        if(!StringUtils.isEmpty(strRelationResult))
            strRelationResult=String.format(" %s ",strRelationResult);

        return strRelationResult;
    }


    private String getFieldkeyset(String fieldName,Hashtable<String,String> modelset)
    {
        String str=this.getFieldset(fieldName, modelset);
        if(str.equals("null"))
            return modelset.get("datamodelname")+".$K()";
        return str+"";
    }

    private String getFieldset(String fieldName,Hashtable<String,String> modelset)
    {
        if(StringUtils.isEmpty(fieldName))
            return "null";
        if(modelset!=null)
        {
            String[] arr=fieldName.split("[.]");
            if(arr.length>=2)
            {
                modelset.put(arr[0],arr[0]);
                if(modelset.containsKey("EXIST"))
                {
                    return modelset.get("EXIST")+".$(\""+	fieldName+"\")";
                }



            }
        }
        return modelset.get("datamodelname")+".$(\""+	fieldName+"\")";
    }

    private String getStaticFieldset(String value,Hashtable<String,String> modelset)
    {
        String staticValue = StringUtils.isEmpty(value)?"":value.replace("\\", "");
        return modelset.get("datamodelname")+".$S(\""+staticValue+"\")";
    }
}

