package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.extensions.mapper.ExecResultExMapper;
import cn.ibizlab.core.rule.domain.ExecResult;
import cn.ibizlab.core.rule.service.IRuleEngineService;
import cn.ibizlab.core.rule.service.impl.ExecResultServiceImpl;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
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 javax.sql.DataSource;
import java.util.*;

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

    public static final String Default_ResultDataSource = "default";
    public static final String Default_ResultTableName = "IBZRULERESULT";

    @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 execResultId = entry.getKey();
                                    String [] idArray = execResultId.split("\\|");
                                    List<ExecResult> execResults = entry.getValue();
                                    List<ExecResult> tempExecResults = new ArrayList<>();
                                    if (execResults.size() > 0 && idArray.length==3) {
                                        for (ExecResult execResult : execResults) {
                                            tempExecResults.add(execResult);
                                            if (tempExecResults.size() >= 500) {
                                                saveResultBatch(tempExecResults, idArray[1] , idArray[2]);
                                                tempExecResults.clear();
                                            }
                                        }
                                        if (tempExecResults.size() > 0) {
                                            saveResultBatch(tempExecResults, idArray[1] , idArray[2]);
                                            tempExecResults.clear();
                                        }
                                        resultsSaveAsync.remove(execResultId);
                                    }
                                }
                            }
                        }
                    } 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 execResultId = entry.getKey();
                                    List<ExecResult> execResults = entry.getValue();
                                    List<ExecResult> tempExecResults = new ArrayList<>();
                                    String [] idArray = execResultId.split("\\|");
                                    if (execResults.size() > 0 && idArray.length==3) {
                                        for (ExecResult execResult : execResults) {
                                            tempExecResults.add(execResult);
                                            if (tempExecResults.size() >= 500) {
                                                clearResultBatch(tempExecResults, idArray[1] , idArray[2]);
                                                tempExecResults.clear();
                                            }
                                        }
                                        if (tempExecResults.size() > 0) {
                                            clearResultBatch(tempExecResults, idArray[1] , idArray[2]);
                                            tempExecResults.clear();
                                        }
                                        resultsDeleteAsync.remove(execResultId);
                                    }
                                }
                            }
                        }
                    } catch (Exception ex) {
                        log.error(ex.getMessage());
                    }
                }
            }, 1000, 10000);
        }
        return et;
    }

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

    @Autowired
    private DstDataSourceExService dstDataSourceService;


    @Autowired
    @Lazy
    private DynamicRoutingDataSource dynamicRoutingDataSource;

    @Autowired
    private ExecResultExMapper execResultExMapper;


    public int saveResultBatch(List<ExecResult> execResults, String dsName ,String tableName) {
        int result = 0;
        try {
            if(!Default_ResultDataSource.equalsIgnoreCase(dsName)) {
                dstDataSourceService.initDataSource(dsName);
                DynamicDataSourceContextHolder.push(dsName);
                Map<String, DataSource> dynamicDSMap = dynamicRoutingDataSource.getCurrentDataSources();
                if (!ObjectUtils.isEmpty(dynamicDSMap) && dynamicDSMap.containsKey(dsName)) {
                    DataSource ds = dynamicDSMap.get(dsName);
                    if (ds instanceof DruidDataSource) {
                        DruidDataSource druidDataSource = (DruidDataSource) dynamicDSMap.get(dsName);
                        if ("oracle".equals(druidDataSource.getDbType())) {
                            return execResultExMapper.replaceBatchByOracle(execResults, tableName);
                        }
                    }
                }
            }
            result = execResultExMapper.replaceBatch(execResults, tableName);
        } catch (Exception ex) {
            log.error("存储规则结果发生异常，详细错误信息：" + ex.getMessage());
        } finally {
            if(!Default_ResultDataSource.equalsIgnoreCase(dsName)) {
                DynamicDataSourceContextHolder.poll();
            }
        }
        return result;
    }

    public int clearResultBatch(List<ExecResult> execResults, String dsName ,String tableName) {
        int result = 0;
        try {
            if(!Default_ResultDataSource.equalsIgnoreCase(dsName)){
                dstDataSourceService.initDataSource(dsName);
                DynamicDataSourceContextHolder.push(dsName);
            }
            result = execResultExMapper.clearBatch(execResults, tableName);
        } catch (Exception ex) {
            log.error("存储规则结果发生异常，详细错误信息：" + ex.getMessage());
        } finally {
            if(!Default_ResultDataSource.equalsIgnoreCase(dsName)) {
                DynamicDataSourceContextHolder.poll();
            }
        }
        return result;
    }

}

