package cn.ibizlab.core.extensions.service;

import cn.ibizlab.core.analysis.domain.DAMetric;
import cn.ibizlab.core.analysis.domain.DAReport;
import cn.ibizlab.core.analysis.service.impl.DAReportServiceImpl;
import cn.ibizlab.core.dict.extensions.service.DictDstService;
import cn.ibizlab.core.extensions.cql.ExecResult;
import cn.ibizlab.core.extensions.cql.ExecResultRepository;
import cn.ibizlab.core.extensions.domain.FetchMetricDatasParam;
import cn.ibizlab.core.lite.domain.MetaModel;
import cn.ibizlab.core.lite.extensions.domain.EntityModel;
import cn.ibizlab.core.lite.extensions.model.DataModel;
import cn.ibizlab.core.lite.extensions.service.LiteModelService;
import cn.ibizlab.core.rule.domain.RuleItem;
import cn.ibizlab.util.dict.CodeItem;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.DataObject;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.datastax.driver.core.PagingState;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class DACoreService {

    @Autowired
    @Lazy
    private DAMetricExService daMetricExService;

    @Autowired(required = false)
    @Lazy
    private ExecResultRepository execResultRepository;

    @Autowired
    @Lazy
    private DictDstService dictDstService;

    @Autowired
    @Lazy
    private DAReportServiceImpl daReportService;

    @Autowired
    @Lazy
    private RuleItemExService ruleItemExService;
    @Autowired
    private LiteModelService liteModelService;

    /**
     * 通过指标、维度、时间获取相应的规则结果数据
     * @param param
     * @return
     */
//    @Cacheable( value="onFetchMetricDatas",keyGenerator="keyGenerator")
    @Cacheable( value="onFetchMetricDatas",key="'onFetchMetricDatas:'+#p0.getMetricids() + '||' + #p0.getDimval() + '||' + #p0.getStarttime() + '||' + #p0.getEndtime()")
    public List<HashMap<String,Object>> onFetchMetricDatas(FetchMetricDatasParam param) {
        List<HashMap<String,Object>> execResults = new ArrayList<HashMap<String,Object>>();
        try {
            if(param == null){
                return execResults;
            }
            List<String> ruleidList = param.getMetricids();
            String strDimval = param.getDimval();
            boolean isIncludeChild = param.isIncludechild();
            String strDIMCodeList = param.getDimcodelist();
            Timestamp timeStartTime = param.getStarttime();
            Timestamp timeEndTime = param.getEndtime();
            execResults = this.getResultIds(ruleidList, strDIMCodeList, strDimval, isIncludeChild, timeStartTime, timeEndTime,"");
        } catch (Exception ex) {
            log.error("获取查询报表错误, 错误原因："+ex.getMessage());
        }
        return execResults;
    }

    /**
     * 呈报报表获取数据
     * @param param
     * @return
     */
//    @Cacheable( value="onFetchReportDatas",keyGenerator="keyGenerator")
    @Cacheable( value="onFetchReportDatas",key="'onFetchReportDatas:'+#p0.getReportid() + '||' + #p0.getDimval() + '||' + #p0.getStarttime() + '||' + #p0.getEndtime()")
    public Map<String, Object> onFetchReportDatas(FetchMetricDatasParam param) {
        Map<String, Object> resultMap = new HashMap<String,Object>();
        try {
            if(param == null){
                return resultMap;
            }
            String id = param.getReportid();
            if (StringUtils.isEmpty(id)) {
                return resultMap;
            }
            //获取表头及表单名称
            DAReport daReport = daReportService.getById(id);
            String vmcfg = daReport != null ? daReport.getConfig() : "";
            String reportname = daReport != null ? daReport.getReportName() : "";
            String strTableDisplayType = param.getTableDisplayType();
            //获取表格数据
            JSONObject jsonObject = this.getERPortData(daReport, param.getDimval(), param.getDimcodelist(), param.getStarttime(), param.getEndtime(), strTableDisplayType,param.getExt_1field());
            resultMap.put("vmcfg",vmcfg);
            resultMap.put("reportname",reportname);
            resultMap.put("resportdata",jsonObject);
        } catch (Exception ex) {
            log.error("获取查询报表错误, 错误原因："+ex.getMessage());
        }
        return resultMap;
    }

    /**
     * 获取反查数据用到的keyvalue
     * @param param
     * @return
     */
//    @Cacheable( value="onFetchKeyValueField",keyGenerator="keyGenerator")
    @Cacheable( value="onFetchKeyValueField",key="'onFetchKeyValueField:' + #p0.getPagingCurrent() + '||' + #p0.getRuleid() + '||' + #p0.getDimval() + '||' + #p0.getStarttime() + '||' + #p0.getEndtime()")
    public Map<String, String> onFetchKeyValueField(FetchMetricDatasParam param) {
        Map<String, String> resultMap = new HashMap<String,String>();
        try {
            String strKeyValue = "";
            if (param == null) {
                return resultMap;
            }
            long lPagingCurrent = param.getPagingCurrent();
            String strRuleid = param.getRuleid();
            String strDimval = param.getDimval();
            Timestamp timeStart = param.getStarttime() == null ? this.getDefaultStartTimestamp() : param.getStarttime();
            Timestamp timeEnd = param.getEndtime() == null ? this.getDefaultEndTimestamp() : param.getEndtime();
            String ext_1field = param.getExt_1field();
            if (StringUtils.isEmpty(strRuleid)) {
                return resultMap;
            }
            resultMap = this.getKeyvaluefields(lPagingCurrent, strRuleid, strDimval, timeStart, timeEnd, ext_1field);
        } catch (Exception ex) {
            log.error("获取查询报表错误, 错误原因："+ex.getMessage());
        }
        return resultMap;
    }

    /**
     * 根据报表ID查询相应的数据
     *
     * @param strDST_CBID
     * @return
     */
    public JSONObject getERPortData(DAReport report, String strLoadDimval, String strDict, Timestamp timeLoadStartTime, Timestamp timeLoadEndTime, String strTableDisplayType, String ext_1field) {
        JSONObject jsonObject = new JSONObject();
        if (report != null) {
            DAReport daReport = report;
            String strVMCFG = daReport.getConfig();
            if (StringUtils.isEmpty(strVMCFG)) {
                throw new BadRequestAlertException("报表配置不存在", "", "");
            }
            List<String> ruleidList = getRuleids(JSONArray.parseArray(strVMCFG));
            String strDimval = StringUtils.isEmpty(strLoadDimval) ? "%" : strLoadDimval;
            strDict = StringUtils.isEmpty(strDict) ? this.getDict(daReport) : strDict;
            Timestamp startTime = timeLoadStartTime == null ? this.getDefaultStartTimestamp() : timeLoadStartTime;
            Timestamp endTime = timeLoadEndTime == null ? this.getDefaultEndTimestamp() : timeLoadEndTime;
            JSONArray jsonArray = new JSONArray();
            List<HashMap<String, Object>> execResults = this.getResultIds(ruleidList, strDict, strDimval, startTime, endTime, ext_1field);
            jsonArray.add(execResults);
            if (!StringUtils.isEmpty(strTableDisplayType) && "LIST_BOX".equals(strTableDisplayType)) {
                JSONArray rowJson = new JSONArray();
                rowJson.addAll(JSONArray.parseArray(strVMCFG));
                jsonObject = this.getErReportHeader(execResults, rowJson);// 行转列模式
            } else {
                jsonObject.put("headData", getVMCFG(strVMCFG, "report"));
                jsonObject.put("erportdata", jsonArray);
            }

        } else {
            throw new BadRequestAlertException("报表不存在", "", "");
        }
        return jsonObject;
    }

    /**
     * 获取指标相关的查询结果数据
     * @param ruleid
     * @param dimval
     * @param start
     * @param end
     * @param ext_1field
     * @return
     */
//    @Cacheable( value="reportinspec",keyGenerator="keyGenerator")
    @Cacheable( value="reportinspec",key="'reportinspec:' + #p0 + '||' + #p1 + '||' + #p2 + '||' + #p3 + '||' + #p4 + '||' + #p5")
    public Map<String, String> getKeyvaluefields(long lPagingCurrent, String ruleid, String dimval, Timestamp start, Timestamp end, String ext_1field)
    {
        Map<String, String> result = null;
        PagingState pagingState = null;
        for (long i=1L;i<=lPagingCurrent;i++) {
            if (lPagingCurrent == i) {
                result = this.page(pagingState, ruleid, 1, dimval, start, end, true, ext_1field);
                break;
            } else {
                result = this.page(pagingState, ruleid, 1, dimval, start, end, false, ext_1field);
            }

            String strPagingState = result.get("pagingState");
            if (!StringUtils.isEmpty(strPagingState)) {
                pagingState = PagingState.fromString(strPagingState);
            }
        }
        return result;
    }

//    @Cacheable( value="reportshow",keyGenerator="keyGenerator")
    @Cacheable( value="reportshow",key="'reportshow:' + #p0 + '||' + #p1 + '||' + #p2 + '||' + #p3 + '||' + #p4 + '||' + #p5")
    public List<HashMap<String,Object>> getResultIds(List<String> metricList, String dimcodelist,String dimval, Timestamp start, Timestamp end, String ext_1field)
    {
        return this.getResultIds(metricList, dimcodelist, dimval, true, start, end, ext_1field);
    }

//    @Cacheable( value="reportshow", keyGenerator="keyGenerator")
    @Cacheable( value="reportshow",key="'reportshow:' + #p0 + '||' + #p1 + '||' + #p2 + '||' + #p3 + '||' + #p4 + '||' + #p5 + '||' + #p6")
    public List<HashMap<String,Object>> getResultIds(List<String> metricList, String dimcodelist, String dimval, boolean includeChild, Timestamp start, Timestamp end, String ext_1field)
    {
        QueryWrapper<DAMetric> sf=new QueryWrapper<>();
        sf.in("da_metricid", metricList);
        return this.getResult(this.daMetricExService.list(sf), dimcodelist, dimval, includeChild, start, end, ext_1field);
    }

    public List<HashMap<String,Object>> getResult(List<DAMetric> metricList, String dimcodelist, String dimval, boolean includeChild, Timestamp start, Timestamp end, String ext_1field)
    {

        List<String> sum=new ArrayList<String>();
        List<String> avg=new ArrayList<String>();

        List<String> sum_yoy=new ArrayList<>();
        List<String> sum_mom=new ArrayList<>();
        List<String> sum_y3=new ArrayList<>();
        List<DAMetric> sum_per=new ArrayList<>();

        List<String> avg_yoy=new ArrayList<>();
        List<String> avg_mom=new ArrayList<>();
        List<String> avg_y3=new ArrayList<>();
        List<DAMetric> avg_per=new ArrayList<>();


        for(DAMetric metric:metricList)
        {
            if("AVG".equals(metric.getMetricType()))
            {
                avg.add(metric.getMetricId());
                if("YOY".equals(metric.getExtOp()))
                    avg_yoy.add(metric.getMetricId());
                else if("MOM".equals(metric.getExtOp()))
                    avg_mom.add(metric.getMetricId());
                else if("Y3".equals(metric.getExtOp()))
                    avg_y3.add(metric.getMetricId());
                else if("PER".equals(metric.getExtOp()) || "PER_ORI".equals(metric.getExtOp()))
                    avg_per.add(metric);

            }
            else
            {
                sum.add(metric.getMetricId());
                if("YOY".equals(metric.getExtOp()))
                    sum_yoy.add(metric.getMetricId());
                else if("MOM".equals(metric.getExtOp()))
                    sum_mom.add(metric.getMetricId());
                else if("Y3".equals(metric.getExtOp()))
                    sum_y3.add(metric.getMetricId());
                else if("PER".equals(metric.getExtOp()) || "PER_ORI".equals(metric.getExtOp()))
                    sum_per.add(metric);
            }
        }
        List<String> dims = new ArrayList<>();

        List<HashMap<String,Object>> dimsObj = new ArrayList<>();
        Hashtable<String,HashMap<String,Object>> dimsSet = new Hashtable<>();

//        CodeItem code=CodeListBase.getCodeList(dimcodelist).getCodeList().getCodeItemModelMap().get(dimval);
        CodeItem code= dictDstService.getCodeListCatalog(dimcodelist).findChildren(dimval);
        if(code==null)
            return null;
        int no=1;
        if(code.getChildren()!=null&&includeChild)
        {
            for(CodeItem item:code.getChildren())
            {
                dims.add(item.getValue().toString());
                HashMap<String,Object> obj=new HashMap<>();
                obj.put("no", no);
                obj.put("dimcode", item.getValue().toString());
                obj.put("dimname", item.getText());

                for(DAMetric metric:metricList)
                {
                    obj.put(metric.getMetricId(), 0d);
                }
                dimsObj.add(obj);
                dimsSet.put(item.getValue().toString(), obj);

                no++;
            }
        }
        boolean bcalsum=false;
        HashMap<String,Object> sumobj=new HashMap<>();
        {
            if(dims.size()==0)
                dims.add(code.getValue().toString());
            else
                bcalsum=true;

            sumobj.put("no", no);
            sumobj.put("dimcode", code.getValue().toString());
            sumobj.put("dimname", "合计");
            for(DAMetric metric:metricList)
            {
                sumobj.put(metric.getMetricId(), 0d);
            }
            dimsObj.add(sumobj);
            dimsSet.put(code.getValue().toString(), sumobj);
        }


        List<ExecResult> list=new ArrayList<>();

        if(sum.size()>0)
        {
//            List<ExecResult> listsum = execResultRepository.sum(sum, 1, dims, start, end);
            List<ExecResult> listsum = new ArrayList<>();
            if (!StringUtils.isEmpty(ext_1field)) {
                listsum = execResultRepository.sum(sum, 1, dims, start, end, ext_1field);
            } else {
                listsum = execResultRepository.sum(sum, 1, dims, start, end);
            }
            list.addAll(listsum);
        }
        if(avg.size()>0)
        {
//            List<ExecResult> listavg = execResultRepository.avg(avg, 1, dims, start, end);
            List<ExecResult> listavg = new ArrayList<>();
            if (!StringUtils.isEmpty(ext_1field)) {
                listavg = execResultRepository.avg(avg, 1, dims, start, end, ext_1field);
            } else {
                listavg = execResultRepository.avg(avg, 1, dims, start, end);
            }
            list.addAll(listavg);
        }

        for(ExecResult res:list)
        {
            if(!dimsSet.containsKey(res.getDimfield()))
                continue;
            HashMap<String,Object> obj=dimsSet.get(res.getDimfield());
            obj.put(res.getRuleid(), res.getMetricfield());
            if(bcalsum)
            {
                Double d=0d;
                if(res.getMetricfield()!=null)
                {
                    d=res.getMetricfield();
                }
                Double sumd=0d;
                if(sumobj.containsKey(res.getRuleid())&&sumobj.get(res.getRuleid())!=null)
                {
                    sumd=(double)sumobj.get(res.getRuleid());
                }
                sumd+=d;
                sumobj.put(res.getRuleid(), sumd);
            }
        }


        //同比
        List<ExecResult> list_yoy=new ArrayList<>();
        if(sum_yoy.size()>0)
        {
//            List<ExecResult> listsum=execResultRepository.sum(sum_yoy, 1, dims, getLastYear(start), getLastYear(end));
            List<ExecResult> listsum = new ArrayList<>();
            if (!StringUtils.isEmpty(ext_1field)) {
                listsum = execResultRepository.sum(sum_yoy, 1, dims, getLastYear(start), getLastYear(end), ext_1field);
            } else {
                listsum = execResultRepository.sum(sum_yoy, 1, dims, getLastYear(start), getLastYear(end));
            }
            list_yoy.addAll(listsum);
        }
        if(avg_yoy.size()>0)
        {
//            List<ExecResult> listavg=execResultRepository.avg(avg_yoy, 1, dims, getLastYear(start), getLastYear(end));
            List<ExecResult> listavg = new ArrayList<>();
            if (!StringUtils.isEmpty(ext_1field)) {
                listavg = execResultRepository.avg(avg_yoy, 1, dims, getLastYear(start), getLastYear(end), ext_1field);
            } else {
                listavg = execResultRepository.avg(avg_yoy, 1, dims, getLastYear(start), getLastYear(end));
            }
            list_yoy.addAll(listavg);
        }

        for(ExecResult res:list_yoy)
        {
            if(!dimsSet.containsKey(res.getDimfield()))
                continue;
            HashMap<String,Object> obj=dimsSet.get(res.getDimfield());
            Double now=(double)obj.get(res.getRuleid());
            Double last=res.getMetricfield();
            if(last==0d)
            {
                last=1d;
                if(now==0d)
                    now=1d;
            }


            Double d=(now-last)/last;
            d=d*100;
            //DecimalFormat df = new DecimalFormat("#.00");
            BigDecimal b = new BigDecimal(d);
            d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

            obj.put(res.getRuleid(), d);
        }

        if(bcalsum)
        {

            HashMap<String,Double> sumlastset=new HashMap<String,Double>();
            for(ExecResult res:list_yoy)
            {
                Double sumlast=0d;
                Double d=0d;
                if(res.getMetricfield()!=null)
                {
                    d=res.getMetricfield();
                }

                if(sumlastset.containsKey(res.getRuleid())&&sumlastset.get(res.getRuleid())!=null)
                {
                    sumlast= sumlastset.get(res.getRuleid());
                }
                sumlast+=d;
                sumlastset.put(res.getRuleid(), sumlast);
            }
            for(String str:sumlastset.keySet())
            {

                Double now=(double)sumobj.get(str);
                Double last=sumlastset.get(str);
                if(last==0d)
                {
                    last=1d;
                    if(now==0d)
                        now=1d;
                }


                Double d=(now-last)/last;
                d=d*100;
                //DecimalFormat df = new DecimalFormat("#.00");
                BigDecimal b = new BigDecimal(d);
                d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

                sumobj.put(str, d);
            }
        }

        //环比
        List<ExecResult> list_mom=new ArrayList<>();
        if(sum_mom.size()>0)
        {
//            List<ExecResult> listsum=execResultRepository.sum(sum_mom, 1, dims, getLastMonth(start), getLastMonth(end));
            List<ExecResult> listsum = new ArrayList<>();
            if (!StringUtils.isEmpty(ext_1field)) {
                listsum = execResultRepository.sum(sum_mom, 1, dims, getLastMonth(start), getLastMonth(end), ext_1field);
            } else {
                listsum = execResultRepository.sum(sum_mom, 1, dims, getLastMonth(start), getLastMonth(end));
            }
            list_mom.addAll(listsum);
        }
        if(avg_mom.size()>0)
        {
//            List<ExecResult> listavg=execResultRepository.avg(avg_mom, 1, dims, getLastMonth(start), getLastMonth(end));
            List<ExecResult> listavg = new ArrayList<>();
            if (!StringUtils.isEmpty(ext_1field)) {
                listavg = execResultRepository.avg(avg_mom, 1, dims, getLastMonth(start), getLastMonth(end), ext_1field);
            } else {
                listavg = execResultRepository.avg(avg_mom, 1, dims, getLastMonth(start), getLastMonth(end));
            }
            list_mom.addAll(listavg);
        }

        for(ExecResult res:list_mom)
        {
            if(!dimsSet.containsKey(res.getDimfield()))
                continue;
            HashMap<String,Object> obj=dimsSet.get(res.getDimfield());
            Double now=(double)obj.get(res.getRuleid());
            Double last=res.getMetricfield();
            if(last==0d)
            {
                last=1d;
                if(now==0d)
                    now=1d;
            }


            Double d=(now-last)/last;
            d=d*100;
            //DecimalFormat df = new DecimalFormat("#.00");
            BigDecimal b = new BigDecimal(d);
            d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

            obj.put(res.getRuleid(), d);
        }

        if(bcalsum)
        {

            HashMap<String,Double> sumlastset=new HashMap<String,Double>();
            for(ExecResult res:list_mom)
            {
                Double sumlast=0d;
                Double d=0d;
                if(res.getMetricfield()!=null)
                {
                    d=res.getMetricfield();
                }

                if(sumlastset.containsKey(res.getRuleid())&&sumlastset.get(res.getRuleid())!=null)
                {
                    sumlast= sumlastset.get(res.getRuleid());
                }
                sumlast+=d;
                sumlastset.put(res.getRuleid(), sumlast);
            }
            for(String str:sumlastset.keySet())
            {

                Double now=(double)sumobj.get(str);
                Double last=sumlastset.get(str);
                if(last==0d)
                {
                    last=1d;
                    if(now==0d)
                        now=1d;
                }


                Double d=(now-last)/last;
                d=d*100;
                //DecimalFormat df = new DecimalFormat("#.00");
                BigDecimal b = new BigDecimal(d);
                d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

                sumobj.put(str, d);
            }
        }

        //占比
        sum_per.addAll(avg_per);

        for(DAMetric res:sum_per)
        {
            boolean isPerOri = false;
            if("PER_ORI".equalsIgnoreCase(res.getExtOp()))
                isPerOri = true;
            for(HashMap<String,Object> obj:dimsObj)
            {
                if (StringUtils.isEmpty(obj.get(res.getMetricId())) || StringUtils.isEmpty(obj.get(res.getRefMetric()))) {
                    continue;
                }
                Double cur=(double)obj.get(res.getMetricId());
                Double per=(double)obj.get(res.getRefMetric());
                if(per==0d)
                    per=1d;
                Double d=(cur)/per;
                if(!isPerOri) {
                    d = d * 100;
                }
                BigDecimal b = new BigDecimal(d);
                d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                obj.put(res.getMetricId(), d);

            }



        }
        return dimsObj;
    }

    /**
     * 清除和绩效考核有关的缓存
     */
    @Caching(evict={@CacheEvict(value = "getPerformanceData", allEntries = true),
            @CacheEvict(value = "sumPerformancePiece", allEntries = true),
            @CacheEvict(value = "getPerformanceReportData", allEntries = true)})
    public void resetPerformance()
    {

    }

    @Caching(evict={@CacheEvict(value = "onFetchMetricDatas", allEntries = true),
            @CacheEvict(value = "onFetchReportDatas", allEntries = true),
            @CacheEvict(value = "onFetchKeyValueField", allEntries = true),
            @CacheEvict(value = "reportshow", allEntries = true),
            @CacheEvict(value = "reportinspec", allEntries = true)})
    public void resetsnap()
    {

    }

    /**
     * 清除获取指标的缓存
     */
//    @CacheEvict(value = "onFetchMetricDatas", allEntries = true)
    @Caching(evict={@CacheEvict(value = "onFetchMetricDatas", allEntries = true),
            @CacheEvict(value = "reportshow", allEntries = true),
            @CacheEvict(value = "reportinspec", allEntries = true)})
    public void resetsnapSingle()
    {

    }

    /**
     * 清除报表的缓存
     */

    @Caching(evict={@CacheEvict(value = "onFetchReportDatas", allEntries = true),
            @CacheEvict(value = "reportshow", allEntries = true),
            @CacheEvict(value = "reportinspec", allEntries = true)})
    public void resetsnapReport()
    {

    }

    /**
     * 根据报表ID查询绩效考核的相应数据
     *
     * @return
     */
    @Cacheable( value="getPerformanceReportData",key="'getPerformanceReportData:' + #p0 + '||' + #p1 + '||' + #p2 + '||' + #p3")
    public Map<String, Object> getPerformanceReportData(DAReport report, List<String> dimfieldList, Timestamp timeLoadStartTime,Timestamp timeLoadEndTime) {
        Map<String, Object> dataMap = new HashMap<String, Object>();
        if (report != null){
            DAReport daReport = report;
            String strVMCFG = daReport.getConfig();
            if (StringUtils.isEmpty(strVMCFG)) {
                throw new BadRequestAlertException("报表配置不存在", "", "");
            }
            List<String> ruleidList = getRuleids(JSONArray.parseArray(strVMCFG));
            Timestamp startTime = timeLoadStartTime == null ? this.getDefaultStartTimestamp() : timeLoadStartTime;
            Timestamp endTime = timeLoadEndTime == null ? this.getDefaultEndTimestamp() : timeLoadEndTime;
            JSONArray jsonArray = new JSONArray();
            List<ExecResult> execResults = getPerformanceData(ruleidList, dimfieldList, startTime, endTime);
            List<ExecResult> performancePieceDatas = sumPerformancePiece(ruleidList, 1, dimfieldList, startTime, endTime);
            jsonArray.add(execResults);
            dataMap.put("headData", getVMCFG(strVMCFG, "JXKH"));
            dataMap.put("erportdata", execResults);
            dataMap.put("ruleidList", ruleidList);
            dataMap.put("performancePieceDatas", performancePieceDatas);
        }else {
            throw new BadRequestAlertException("报表不存在", "", "");
        }
        return dataMap;
    }

    /**
     * 获取绩效考核数据
     * @param metricList
     * @param dimfieldList
     * @param start
     * @param end
     * @return
     */
    @Cacheable( value="getPerformanceData",key="'getPerformanceData:' + #p0 + '||' + #p1 + '||' + #p2 + '||' + #p3")
    public List<ExecResult> getPerformanceData(List<String> metricList, List<String> dimfieldList, Timestamp start, Timestamp end) {
        List<ExecResult> list = new ArrayList<ExecResult>();

        List<String> sum=new ArrayList<String>();
        List<String> avg=new ArrayList<String>();

        List<String> sum_yoy=new ArrayList<>();
        List<String> sum_mom=new ArrayList<>();
        List<String> sum_y3=new ArrayList<>();
        List<DAMetric> sum_per=new ArrayList<>();

        List<String> avg_yoy=new ArrayList<>();
        List<String> avg_mom=new ArrayList<>();
        List<String> avg_y3=new ArrayList<>();
        List<DAMetric> avg_per=new ArrayList<>();

        QueryWrapper<DAMetric> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("da_metricid", metricList);
        List<DAMetric> metricAllList = this.daMetricExService.list(queryWrapper);
        for(DAMetric metric:metricAllList)
        {
            if("AVG".equals(metric.getMetricType()))
            {
                avg.add(metric.getMetricId());
                if("YOY".equals(metric.getExtOp()))
                    avg_yoy.add(metric.getMetricId());
                else if("MOM".equals(metric.getExtOp()))
                    avg_mom.add(metric.getMetricId());
                else if("Y3".equals(metric.getExtOp()))
                    avg_y3.add(metric.getMetricId());
                else if("PER".equals(metric.getExtOp()) || "PER_ORI".equals(metric.getExtOp()))
                    avg_per.add(metric);

            }
            else
            {
                sum.add(metric.getMetricId());
                if("YOY".equals(metric.getExtOp()))
                    sum_yoy.add(metric.getMetricId());
                else if("MOM".equals(metric.getExtOp()))
                    sum_mom.add(metric.getMetricId());
                else if("Y3".equals(metric.getExtOp()))
                    sum_y3.add(metric.getMetricId());
                else if("PER".equals(metric.getExtOp()) || "PER_ORI".equals(metric.getExtOp()))
                    sum_per.add(metric);
            }
        }

        if (dimfieldList == null || dimfieldList.size() == 0) {
            return list;
        }

        if (sum.size() > 0) {
            List<ExecResult> listsum = execResultRepository.sum(sum, 1, dimfieldList, start, end);
            list.addAll(listsum);
        }
        if(avg.size()>0)
        {
            List<ExecResult> listavg=execResultRepository.avg(avg, 1, dimfieldList, start, end);
            list.addAll(listavg);
        }

        //同比
        List<ExecResult> list_yoy=new ArrayList<>();
        if(sum_yoy.size()>0)
        {
            List<ExecResult> listsum=execResultRepository.sum(sum_yoy, 1, dimfieldList, getLastYear(start), getLastYear(end));
            list_yoy.addAll(listsum);
        }
        if(avg_yoy.size()>0)
        {
            List<ExecResult> listavg=execResultRepository.avg(avg_yoy, 1, dimfieldList, getLastYear(start), getLastYear(end));
            list_yoy.addAll(listavg);
        }

        List<ExecResult> list_all_yoy = new ArrayList<>();
        for(ExecResult res:list_yoy)
        {
//            HashMap<String,Object> obj=dimsSet.get(res.getDimfield());
            Double now = res.getMetricfield();
            Double last=res.getMetricfield();
            if(last==0d)
            {
                last=1d;
                if(now==0d)
                    now=1d;
            }


            Double d=(now-last)/last;
            d=d*100;
            //DecimalFormat df = new DecimalFormat("#.00");
            BigDecimal b = new BigDecimal(d);
            d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            res.setMetricfield(d);
            list_all_yoy.add(res);
//            obj.put(res.getRuleid(), d);
        }
        list.addAll(list_all_yoy);

        //环比
        List<ExecResult> list_mom=new ArrayList<>();
        if(sum_mom.size()>0)
        {
            List<ExecResult> listsum=execResultRepository.sum(sum_mom, 1, dimfieldList, getLastMonth(start), getLastMonth(end));
            list_mom.addAll(listsum);
        }
        if(avg_mom.size()>0)
        {
            List<ExecResult> listavg=execResultRepository.avg(avg_mom, 1, dimfieldList, getLastMonth(start), getLastMonth(end));
            list_mom.addAll(listavg);
        }
        List<ExecResult> list_all_mom=new ArrayList<>();
        for(ExecResult res:list_mom)
        {
//            if(!dimsSet.containsKey(res.getDimfield()))
//                continue;
//            HashMap<String,Object> obj=dimsSet.get(res.getDimfield());
            Double now=res.getMetricfield();
            Double last=res.getMetricfield();
            if(last==0d)
            {
                last=1d;
                if(now==0d)
                    now=1d;
            }


            Double d=(now-last)/last;
            d=d*100;
            //DecimalFormat df = new DecimalFormat("#.00");
            BigDecimal b = new BigDecimal(d);
            d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            res.setMetricfield(d);

            list_all_mom.add(res);
//            obj.put(res.getRuleid(), d);
        }
        list.addAll(list_all_mom);

        //占比
        sum_per.addAll(avg_per);

        for(DAMetric res:sum_per)
        {
            Map<String, ExecResult> cur_map = new HashMap<>();
            Map<String, ExecResult> per_map = new HashMap<>();
            for(ExecResult execResult : list)
            {
                if ((execResult.getRuleid()).equals(res.getMetricId())) {
                    cur_map.put(execResult.getDimfield(), execResult);
                } else if ((execResult.getRuleid()).equals(res.getRefMetric())) {
                    per_map.put(execResult.getDimfield(), execResult);
                }
            }

            for (String pcrid:dimfieldList) {
                boolean isPerOri = false;
                if("PER_ORI".equalsIgnoreCase(res.getExtOp()))
                    isPerOri = true;
                if (cur_map.containsKey(pcrid)  && per_map.containsKey(pcrid)) {
                    Double cur = cur_map.get(pcrid).getMetricfield();
                    Double per = per_map.get(pcrid).getMetricfield();
                    if(per==0d)
                        per=1d;
                    Double d=(cur)/per;
//                    d=d*100;
                    if(!isPerOri) {
                        d = d * 100;
                    }
                    BigDecimal b = new BigDecimal(d);
                    d = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                    cur_map.get(pcrid).setMetricfield(d);
                }
            }

        }

        return list;
    }

    /**
     * 获取绩效考核数据 （案件数）
     * @param ruleids
     * @param retValue
     * @param dims
     * @param start
     * @param end
     * @return
     */
    @Cacheable( value="getPerformanceData",key="'getPerformanceData:' + #p0 + '||' + #p2 + '||' + #p3 + '||' + #p4")
    public List<ExecResult> sumPerformancePiece(List<String> ruleids, Integer retValue, List<String> dims, Timestamp start, Timestamp end) {
        List<ExecResult> listsum = execResultRepository.sumPerformancePiece(ruleids, 1, dims, start, end);
        return listsum;
    }

    /**
     * 获取以单位为表头的表格数据结构
     * @param execResults
     * @param rowJson
     * @return
     */
    public JSONObject getErReportHeader(List<HashMap<String, Object>> execResults, JSONArray rowJson) {
        JSONObject allData = new JSONObject();
        JSONArray Vmcfg = new JSONArray();
        if (execResults == null || execResults.size() == 0) {
            return allData;
        }
        JSONObject employeeIdRowJson = new JSONObject();
        employeeIdRowJson.put("field", "employeeId");
        employeeIdRowJson.put("hide", true);
//        employeeIdRowJson.put("width", 150);
        Vmcfg.add(employeeIdRowJson);
        JSONObject no = new JSONObject();
        no.put("headerName", "");
//        no.put("width", 80);
        no.put("hide", true);
//        no.put("entity", "TEST");
        no.put("field", "employeeName");
        no.put("pinned", "left");
        Vmcfg.add(no);
        JSONArray allRowData = new JSONArray();
        int iStart = 100;
        JSONArray initTreeJson = this.initGroupTreeData(rowJson, iStart, true);// 初始化表格数据
        try {
            for (HashMap<String, Object> dataMap:execResults) {
                JSONObject headerJson = new JSONObject();
                String strDimname = DataObject.getStringValue(dataMap.get("dimname"), "");
                String strDimcode = DataObject.getStringValue(dataMap.get("dimcode"), "");
                headerJson.put("headerName", strDimname);
                headerJson.put("entity", "TEST");
//                headerJson.put("width", 80);
                headerJson.put("field", strDimcode);
                Vmcfg.add(headerJson);// 设置表头
                // 设置表格数据
                this.setReportRowData(initTreeJson, dataMap, allRowData, true);
            }
            allRowData = initTreeJson;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        JSONArray jsonArray = new JSONArray();
        jsonArray.add(allRowData);
        allData.put("headData", Vmcfg);
        allData.put("erportdata", jsonArray);
        return allData;
    }

    /**
     * 设置表格的数据
     * @param jsonArray
     * @param dataMap
     * @param allRowData
     * @param isInstall
     * @return
     */
    public JSONArray setReportRowData(JSONArray jsonArray, HashMap<String, Object> dataMap, JSONArray allRowData, boolean isInstall) {
        JSONArray allRowDataJson = new JSONArray();
        if (isInstall) {
            allRowDataJson = allRowData;
        }
        if (jsonArray == null || dataMap == null || dataMap.size() == 0) {
            return allRowDataJson;
        }
        try {

            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String strField = jsonObject.getString("field");
                JSONArray childrenJson = jsonObject.getJSONArray("children");
                JSONObject treeRowData = new JSONObject();
                if (!StringUtils.isEmpty(strField) && dataMap.containsKey(strField)) {
                    String strDimcode = DataObject.getStringValue(dataMap.get("dimcode"), "");
                    Double strNumber = DataObject.getDoubleValue(dataMap.get(strField), 0d);
                    jsonObject.put(strDimcode, strNumber);
                }
                if (childrenJson != null && childrenJson.size() > 0) {
                    JSONArray headerChildrenJson = this.setReportRowData(childrenJson, dataMap, allRowDataJson, false);
                    treeRowData.put("children", headerChildrenJson);
                }
//                allRowDataJson.add(treeRowData);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return allRowDataJson;
    }

    /**
     * 初始化表格数据
     * @param jsonArray
     * @param employeeId
     * @param isSum
     * @return
     */
    public JSONArray initGroupTreeData(JSONArray jsonArray, int employeeId, boolean isSum) {
        JSONArray groupData = new JSONArray();
        if (jsonArray == null) {
            return jsonArray;
        }
        try {
            int no = employeeId;
            for (int i = 0; i < jsonArray.size(); i++) {
                if (isSum) {
                    no = employeeId*(i+1);
                    isSum = false;
                }
                no++;
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String strHeaderName = jsonObject.getString("headerName");
                String strField = jsonObject.getString("field");
                String strEntity = jsonObject.getString("entity");
                JSONArray childrenJson = jsonObject.getJSONArray("children");
                JSONObject treeRowData = new JSONObject();
                treeRowData.put("employeeName", strHeaderName);
                treeRowData.put("employeeId", no);
                treeRowData.put("entity", strEntity);
                if (!StringUtils.isEmpty(strField)) {
                    treeRowData.put("field", strField);
                }
                if (childrenJson != null && childrenJson.size() > 0) {
                    JSONArray headerChildrenJson = this.initGroupTreeData(childrenJson, no, false);
                    treeRowData.put("children", headerChildrenJson);
                    isSum = true;
                }
                groupData.add(treeRowData);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return groupData;
    }

    /**
     * 获取查询指标清单
     *
     * @param jsonArray
     * @return
     */
    public List<String> getRuleids(JSONArray jsonArray) {
        List<String> ruleidList = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String strField = jsonObject.getString("field");
            jsonObject.getString("field");

            if (jsonObject.containsKey("children")) {
                JSONArray childrenJson = jsonObject.getJSONArray("children");
                if (childrenJson != null) {
                    ruleidList.addAll(this.getRuleids(childrenJson));
                }
            }

            if (!StringUtils.isEmpty(strField))
                ruleidList.add(strField);
        }
        return ruleidList;
    }

    /**
     * 获取报表的数据字典
     * @param daReport
     * @return
     */
    public String getDict(DAReport daReport) {
//        String strDict = "DST_cl_dst_region";
        String strDict = "CL_DST_REGION";
        if (daReport != null && !StringUtils.isEmpty(daReport.getDict())) {
//            strDict = "DST_"+daReport.getDict();
            strDict = daReport.getDict();
        }
        return strDict;
    }

    public JSONArray getVMCFG(String strVMCFG, String strType) {
        JSONArray Vmcfg = new JSONArray();
        JSONObject no = new JSONObject();
        JSONObject dimname = new JSONObject();
        if (!StringUtils.isEmpty(strType) && "JXKH".equals(strType)) {
            dimname.put("headerName", "承办人");
            no.put("headerName", "单位");
            no.put("width", 150);
        } else {
            dimname.put("headerName", "地区");
            no.put("headerName", "序号");
            no.put("width", 80);
        }
        no.put("entity", "TEST");
        no.put("field", "no");
        no.put("pinned", "left");

        dimname.put("entity", "TEST");
        dimname.put("field", "dimname");
        dimname.put("width", 120);
        dimname.put("pinned", "left");
        Vmcfg.add(no);
        Vmcfg.add(dimname);
        Vmcfg.addAll(JSONArray.parseArray(strVMCFG));
        this.setHeaderEntity(Vmcfg);
        return Vmcfg;
    }

    /**
     * 增加设置报表指标的实体
     * @param jsonArray
     * @return
     */
    public JSONArray setHeaderEntity(JSONArray jsonArray) {
        JSONArray resultJson = new JSONArray();
        if (jsonArray == null || jsonArray.size() == 0) {
            return resultJson;
        }
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject cellJson = jsonArray.getJSONObject(i);
            String strField = cellJson.getString("field");
            if (!StringUtils.isEmpty(strField)) {
                RuleItem dstRule = this.ruleItemExService.getById(strField);
                if (dstRule != null) {
                    String strEntityName = dstRule.getRuleName();
                    MetaModel model = dstRule.getModel();
                    if (!StringUtils.isEmpty(model)){
                        String modelid = model.getId();
                        DataModel dataModel = liteModelService.getDataModel(modelid);
                        if (dataModel != null){
                            EntityModel entityModel = dataModel.getFactEntityModel();
                            if (entityModel != null && entityModel.getEntity() != null){
                                strEntityName = entityModel.getEntity().getEntityName();
                            }
                        }
                    }
                    cellJson.put("entity", strEntityName);
                }
            } else {
                JSONArray childrenJson = cellJson.getJSONArray("children");
                if (childrenJson != null) {
                    this.setHeaderEntity(childrenJson);
                }
            }

        }
        return resultJson;
    }

    public Map<String, String> page(PagingState pagingState, String ruleid, Integer retValue, String dims, Timestamp start, Timestamp end, boolean bResolve, String ext_1field) {

        Map<String, String> result = new HashMap<String, String>();
        List<String> keyvaluefield = new ArrayList<String>();
        // 查询数据
        ResultSet rs = null;
        if (!StringUtils.isEmpty(ext_1field)){
            rs = execResultRepository.getPageData(ruleid, pagingState, retValue, dims, start, end, ext_1field);
        }else {
            rs = execResultRepository.getPageData(ruleid, pagingState, retValue, dims, start, end);
        }
        // 分页信息处理
        PagingState resultpagingState = rs.getExecutionInfo().getPagingState();
        String strPagingState = "";
        if (resultpagingState != null) {
            strPagingState = resultpagingState.toString();
        }
        result.put("pagingState", strPagingState);

        // 代码实现跳页查询，bResolve等于TRUE表示真正要查询的页数
        if (!bResolve) {
            return result;
        }

        //请注意，我们不依赖RESULTS_PER_PAGE，因为fetch size并不意味着cassandra总是返回准确的结果集
        //它可能返回比fetch size稍微多一点或者少一点，另外，我们可能在结果集的结尾
        int remaining = rs.getAvailableWithoutFetching();
        StringBuilder stringBuilder = new StringBuilder();

        for (Row row : rs) {
            String strSymbolKeyValue = String.format("\'%s\', ", row.getString("keyvaluefield"));
            stringBuilder.append(strSymbolKeyValue);
            if (--remaining == 0) {
                break;
            }
        }
        String strKeyValues = "";
        if (stringBuilder != null && stringBuilder.length() > 0) {
            String strKeyValueLists = stringBuilder.toString();
            strKeyValues = strKeyValueLists.substring(0, strKeyValueLists.length() - 2);
        }
        result.put("datas", strKeyValues);
        return result;
    }

    public static Timestamp getDefaultStartTimestamp() {
        Calendar c = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date d=new Date();
        try {
            d = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        c.setTime(d);
        c.add(Calendar.MONTH, -1);

        c.set(Calendar.DAY_OF_MONTH, 1);

        return new Timestamp(c.getTime().getTime());
    }

    public static Timestamp getDefaultEndTimestamp() {
        Calendar c = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date d=new Date();
        try {
            d = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        c.setTime(d);
        int month=c.get(Calendar.MONTH);
        c.set(Calendar.MONTH, month-1);
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        return new Timestamp(c.getTime().getTime());
    }

    /**
     * 时间转换
     * @param strTimp
     * @return
     */
    public static Timestamp getTimestamp(String strTimp) {
        Timestamp timestamp = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat simpleDateFormatTwo = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat simpleDateFormatCST = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
        SimpleDateFormat simpleDateFormatGMT = new SimpleDateFormat("EEE MMM ddHH:mm:ss 'GMT' yyyy",Locale.US);
        SimpleDateFormat simpleDateFormatUTC = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        try {
            if(!StringUtils.isEmpty(strTimp) && !("null".equals(strTimp))) {
                Date date = null;
                if (strTimp.indexOf("CST") >= 0) {
                    date = simpleDateFormatCST.parse(strTimp);
                    timestamp = new Timestamp(date.getTime());
                    return timestamp;
                }
                if (strTimp.indexOf("GMT") >= 0) {
                    date = simpleDateFormatGMT.parse(strTimp);
                    timestamp = new Timestamp(date.getTime());
                    return timestamp;
                }
                if (strTimp.indexOf("UT") >= 0) {
                    date = simpleDateFormatUTC.parse(strTimp);
                    timestamp = new Timestamp(date.getTime());
                    return timestamp;
                }
                if (strTimp.length() == 19) {
                    date = simpleDateFormatTwo.parse(strTimp);
                    timestamp = new Timestamp(date.getTime());
                    return timestamp;
                }
                if(StringUtils.countOccurrencesOf("now", strTimp) != 0) {//strTimp等于now表示获取当前时间
                    date = new Date();
                }else {
                    date = simpleDateFormat.parse(strTimp);
                }
                timestamp = new Timestamp(date.getTime());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return timestamp;
    }

    public Timestamp getLastYear(Timestamp time)
    {
        Date date=new Date(time.getTime());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置为当前时间
        calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
        // 设置为上一年
        date = calendar.getTime();

        Timestamp rt=new Timestamp(date.getTime());
        return rt;
    }

    public Timestamp getLastMonth(Timestamp time)
    {

        Date date=new Date(time.getTime());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置为当前时间
        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
        // 设置为上一个月
        date = calendar.getTime();

        Timestamp rt=new Timestamp(date.getTime());
        return rt;
    }

    @Caching(evict={@CacheEvict( value="reportshow",key="'reportshow:' + #p0.getMetricids() + '||' + #p0.getDimcodelist() + '||' + #p0.getDimval() + '||' + #p0.isIncludechild() + '||' + #p0.getStarttime() + '||' + #p0.getEndtime()+ '||' + #p0.getExt_1field()"),
            @CacheEvict( value="onFetchMetricDatas",key="'onFetchMetricDatas:'+#p0.getMetricids() + '||' + #p0.getDimval() + '||' + #p0.getStarttime() + '||' + #p0.getEndtime()")})
    public void resetCache(FetchMetricDatasParam param){

    }

}
