package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.analysis.domain.DABuild;
import cn.ibizlab.core.analysis.domain.DADimension;
import cn.ibizlab.core.analysis.domain.DAMetric;
import cn.ibizlab.core.analysis.service.IDAMetricService;
import cn.ibizlab.core.analysis.service.impl.DABuildServiceImpl;
import cn.ibizlab.core.extensions.domain.BaseRequest;
import cn.ibizlab.core.extensions.domain.EngineMQMsg;
import cn.ibizlab.core.extensions.util.DefaultMQProducerService;
import cn.ibizlab.core.extensions.util.MQConsumeMsgListenerProcessor;
import cn.ibizlab.core.lite.extensions.domain.EntityObj;
import cn.ibizlab.core.lite.extensions.model.DataModel;
import cn.ibizlab.core.lite.extensions.service.LiteDataCallback;
import cn.ibizlab.core.lite.extensions.service.LiteDataService;
import cn.ibizlab.core.lite.extensions.service.LiteModelService;
import cn.ibizlab.core.rule.domain.ExecLog;
import cn.ibizlab.core.rule.domain.RuleItem;
import cn.ibizlab.core.rule.service.IExecLogService;
import cn.ibizlab.core.rule.service.IRuleItemService;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.CachedBeanCopier;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;


/**
 * 实体[分析] 自定义服务对象
 */
@Slf4j
@Primary
@Service("DABuildExService")
public class DABuildExService extends DABuildServiceImpl {

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

    @Autowired
    protected IExecLogService ruExecLogService;

    @Autowired
    private IDAMetricService idaMetricService;

    @Autowired
    private IRuleItemService ruleItemService;

    @Autowired
    private DefaultMQProducerService defaultMQProducerService;

    @Autowired
    private LiteModelService liteModelService;

    @Autowired
    @Lazy
    private LiteDataService liteDataService;

    @Autowired
    @Qualifier("AnalyseEntityServiceImpl")
    private BaseEntityService analyseEntityServiceImpl;

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

    /**
     * [Check:校验] 行为扩展
     * @param et
     * @return
     */
    @Override
    @Transactional
    public DABuild check(DABuild et) {
        if(!StringUtils.isEmpty(et.getBuildId())) {
            CachedBeanCopier.copy(get(et.getBuildId()), et);

            idaMetricService.list(Wrappers.<DAMetric>lambdaQuery()
                    .eq(DAMetric::getBuildId,et.getBuildId()))
                    .forEach(dametric -> {
                        idaMetricService.update(dametric);

                    });
        }
        return super.check(et);
    }
    /**
     * [ExportFile:导出文件] 行为扩展：导出模型的文件
     * @param et
     * @return
     */
    @Override
    @Transactional
    public DABuild exportFile(DABuild et) {
        return super.exportFile(et);
    }
    /**
     * [Run:运行] 行为扩展
     * @param et
     * @return
     */
    @Override
    public DABuild run(DABuild et) {
        if(!StringUtils.isEmpty(et.getBuildId()))
        {
            CachedBeanCopier.copy(get(et.getBuildId()), et);

            if("RUNNING".equalsIgnoreCase(et.getState()))
                throw new BadRequestAlertException("构建正在执行中，不能重复执行","DABuild",et.getBuildId());

            BaseRequest msg=new BaseRequest();
            msg.setId(IdWorker.getIdStr());
            msg.setModel(et.getModelName());
            msg.setEngineId(et.getBuildId());


            java.sql.Timestamp starttime = new java.sql.Timestamp(System.currentTimeMillis());

            liteDataService.processDataModel(et.getModelId(), et.getLastRuntime(), new LiteDataCallback<List<EntityObj>>() {
                @Override
                public void total(Integer total) {
                    String state = "FINISH";
                    if(total > 0)
                        state = "RUNNING";
                    et.setTotal(total);
                    et.setProcessed(0);
                    et.setState(state);
                    update(et);
                }

                @Override
                public boolean processData(List<EntityObj> datas) {
                    EngineMQMsg engineMQMsg = new EngineMQMsg();
                    engineMQMsg.setEngineId(et.getBuildId());
                    engineMQMsg.setBatch(msg.getBatch());
                    engineMQMsg.setRunTime(starttime);
                    engineMQMsg.setCount(datas.size());
                    engineMQMsg.setDatas(datas);
                    try {
                        defaultMQProducerService.sendToMQ(engineMQMsg, MQConsumeMsgListenerProcessor.Type_Build);
                    } catch (Exception ex) {
                        return false;
                    }
                    return true;
                }
            });


        }
        return super.run(et);
    }


    public void processData(EngineMQMsg engineMQMsg){
        DABuild et = get(engineMQMsg.getEngineId());
        try{
            BaseRequest msg=new BaseRequest();
            msg.setId(IdWorker.getIdStr());
            msg.setModel(et.getModelName());
            msg.setBatch(engineMQMsg.getBatch());
            msg.setSystemid(et.getSystemId());
            msg.setEngineId(engineMQMsg.getEngineId());

            ExecLog execlog=new ExecLog();
            execlog.setId(msg.getId());
            execlog.setName(msg.getBatch());
            execlog.setKeyValueField(msg.getModel());
            execlog.setSystemId(msg.getSystemid());
            ruExecLogService.create(execlog);

            List<String> ruleIds = new ArrayList<>();
            List<String> rulePaths = new ArrayList<>();
            DataModel dataModel=liteModelService.getDataModel(et.getModelId());
            HashSet<String> fillpropertys=new HashSet<>();

            List<String> metrics = new ArrayList<>();
            idaMetricService.list(Wrappers.<DAMetric>lambdaQuery().eq(DAMetric::getBuildId,et.getBuildId()))
                    .forEach(daMetric -> {
                        metrics.add(daMetric.getMetricId());
                    });

            if(metrics.size() == 0){
                log.error(String.format("构建数据失败：未配置指标"));
                return;
            }

            ruleItemService.list(Wrappers.<RuleItem>lambdaQuery().in(RuleItem::getRuleId, metrics))
                    .forEach(ruleItem -> {
                        String path=rulePath + ruleItem.getGroup() + File.separator + ruleItem.getRuleId() + ".drl";
                        File file=new File(path);
                        if(!file.exists())
                        {
                            ruleItemService.buildRuleFile(ruleItem);
                        }
                        if(file.exists())
                        {
                            rulePaths.add(path);
                            ruleIds.add(ruleItem.getRuleId());
                        }
                        if((!StringUtils.isEmpty(ruleItem.getCond()))&&ruleItem.getCond().startsWith("["))
                            fillpropertys.addAll(JSON.toJavaObject(JSON.parseArray(ruleItem.getCond()), LinkedHashSet.class));
                    });

            if(ruleIds.size() == 0){
                log.error(String.format("构建数据失败：无有效规则"));
                return;
            }

            dataModel.getAllProperty().forEach(prop->{
                if(fillpropertys.contains(prop.getPropertyName()))
                {
                    DataModel p=prop.getOwnerDataModel().getParentDataModel();
                    while (p!=null)
                    {
                        fillpropertys.add(p.getFactPorperty().getPropertyName());
                        p=p.getParentDataModel();
                    }
                }
            });

            msg.setRuleIds(ruleIds);
            msg.setRules(rulePaths);
            msg.setDatas(liteDataService.getModelObjs(et.getModelId(),fillpropertys,engineMQMsg.getDatas()));

            analyseEntityServiceImpl.processAll(msg);

        }catch (Exception ex){
            log.error(String.format("构建数据错误：%1$s", ex.getMessage()));
            ex.printStackTrace();
        }

        String updateSql = "UPDATE ibzdabuild SET processed=(CASE WHEN processed is null then 0 else processed end+#{et.count}),lastruntime=CASE WHEN total <= processed THEN #{et.runtime} ELSE lastruntime END," +
                "BUILDSTATE=CASE WHEN total <= processed THEN 'FINISH' ELSE BUILDSTATE END WHERE buildid = #{et.engineId}";
        HashMap<String, Object> param = new HashMap<>();
        param.put("count", engineMQMsg.getCount());
        param.put("runtime", engineMQMsg.getRunTime());
        param.put("engineId", engineMQMsg.getEngineId());
        this.execute(updateSql, param);
    }


    @Cacheable(value ="dabuilddims", key = "'row:'+#p0")
    public List<DADimension>  getDims(String id)
    {
        return this.get(id).getDadimension();
    }

    @Override
    @Transactional
    @CacheEvict(value ={"dabuild","dabuilddims"}, key = "'row:'+#p0.buildId")
    public boolean update(DABuild et) {
        return super.update(et);
    }
}

