package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.lite.extensions.service.DbEntityService;
import cn.ibizlab.core.rule.domain.ExecResult;
import cn.ibizlab.core.rule.domain.RuleEngine;
import cn.ibizlab.core.rule.service.IRuleEngineService;
import cn.ibizlab.core.rule.service.impl.ExecResultServiceImpl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 实体[执行结果] 自定义服务对象
 */
@Slf4j
@Primary
@Service("ExecResultExService")
public class ExecResultExService extends ExecResultServiceImpl {

    @Autowired
    public DbEntityService dbEntityService;

    @Autowired
    @Lazy
    public IRuleEngineService engineService;

    private Map<String, List<ExecResult>> resultsSaveAsync = new HashMap<>();
    private Object objResultSaveAsyncLock = new Object();
    private Timer timerSaveAsync = null;

    private Map<String, List<ExecResult>> resultsDeleteAsync = new HashMap<>();
    private Object objResultDeleteAsyncLock = new Object();
    private Timer timerDeleteAsync = null;

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

    /**
     * [SaveAsync:SaveAsync] 行为扩展
     *
     * @param et
     * @return
     */
    @Override
    @Transactional
    public ExecResult saveAsync(ExecResult et) {
        synchronized (objResultSaveAsyncLock) {
            addExecResult(resultsSaveAsync, et);
        }
        //创建一个定时器
        if (timerSaveAsync == null) {
            timerSaveAsync = new Timer();
            //schedule方法是执行时间定时任务的方法
            timerSaveAsync.schedule(new TimerTask() {
                //run方法就是具体需要定时执行的任务
                @Override
                public void run() {
                    try {
                        synchronized (objResultSaveAsyncLock) {
                            if (resultsSaveAsync.size() > 0) {
                                for (Map.Entry<String, List<ExecResult>> entry : resultsSaveAsync.entrySet()) {
                                    String engineId = entry.getKey();
                                    String dsName = getDSNameByEngineId(engineId);
                                    List<ExecResult> execResults = entry.getValue();
                                    List<ExecResult> tempExecResults = new ArrayList<>();
                                    if (execResults.size() > 0) {
                                        for (ExecResult execResult : execResults) {
                                            tempExecResults.add(execResult);
                                            if (tempExecResults.size() >= 500) {
                                                dbEntityService.saveResultBatch(tempExecResults, dsName);
                                                tempExecResults.clear();
                                            }
                                        }
                                        if (tempExecResults.size() > 0) {
                                            dbEntityService.saveResultBatch(tempExecResults, dsName);
                                            tempExecResults.clear();
                                        }
                                        resultsSaveAsync.remove(engineId);
                                    }
                                }
                            }
                        }
                    } catch (Exception ex) {
                        log.error(ex.getMessage());
                    }
                }
            }, 1000, 10000);
        }
        return et;
    }

    /**
     * [DeleteAsync:DeleteAsync] 行为扩展
     *
     * @param et
     * @return
     */
    @Override
    @Transactional
    public ExecResult deleteAsync(ExecResult et) {
        synchronized (objResultDeleteAsyncLock) {
            addExecResult(resultsDeleteAsync, et);
        }
        if (timerDeleteAsync == null) {
            timerDeleteAsync = new Timer();
            //schedule方法是执行时间定时任务的方法
            timerDeleteAsync.schedule(new TimerTask() {

                //run方法就是具体需要定时执行的任务
                @Override
                public void run() {
                    try {
                        synchronized (objResultDeleteAsyncLock) {
                            if (resultsDeleteAsync.size() > 0) {
                                for (Map.Entry<String, List<ExecResult>> entry : resultsDeleteAsync.entrySet()) {
                                    String engineId = entry.getKey();
                                    String dsName = getDSNameByEngineId(engineId);
                                    List<ExecResult> execResults = entry.getValue();
                                    List<ExecResult> tempExecResults = new ArrayList<>();
                                    if (execResults.size() > 0) {
                                        for (ExecResult execResult : execResults) {
                                            tempExecResults.add(execResult);
                                            if (tempExecResults.size() >= 500) {
                                                dbEntityService.clearResultBatch(tempExecResults, dsName);
                                            }
                                        }
                                        if (tempExecResults.size() > 0) {
                                            dbEntityService.clearResultBatch(tempExecResults, dsName);
                                        }
                                        resultsDeleteAsync.remove(engineId);
                                    }
                                }
                            }
                        }
                    } catch (Exception ex) {
                        log.error(ex.getMessage());
                    }
                }
            }, 1000, 10000);
        }
        return et;
    }

    /**
     * 通过引擎获取数据源信息
     *
     * @param engineId
     * @return
     */
    private String getDSNameByEngineId(String engineId) {
        String dsName = "";
        RuleEngine engine = engineService.get(engineId);
        if (!ObjectUtils.isEmpty(engine.getExtParams())) {
            JSONArray array = JSONArray.parseArray(engine.getExtParams());
            for (int a = 0; a < array.size(); a++) {
                JSONObject engineParam = array.getJSONObject(a);
                String property = engineParam.getString("property");
                String value = engineParam.getString("value");
                if (!StringUtils.isEmpty(property) && RuleEngineExService.Setting_ResultDataSource.equalsIgnoreCase(property) && !StringUtils.isEmpty(value)) {
                    return value;
                }
            }
        }
        return dsName;
    }


    /**
     * 将规则执行结果添加到待保存集合中
     *
     * @param execResultMap
     * @param execResult
     */
    private void addExecResult(Map<String, List<ExecResult>> execResultMap, ExecResult execResult) {
        Object engineId = execResult.get(BaseEntityServiceImpl.Tag_EngineId);
        if (ObjectUtils.isEmpty(engineId)) {
            log.error("存储规则结果失败，无法数据[{}]的引擎标识!", execResult.getId());
            return;
        }
        String strEngine = String.valueOf(engineId);
        if (execResultMap.containsKey(engineId)) {
            execResultMap.get(engineId).add(execResult);
        } else {
            execResultMap.put(strEngine, new ArrayList() {{
                add(execResult);
            }});
        }

    }
}

