package com.ruoyi.projetctCost.task;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.Installationcost.domain.MesInfoInstallationcost;
import com.ruoyi.Installationcost.service.IMesInfoInstallationcostService;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.kyTask.service.IKyTaskInfoService;
import com.ruoyi.mesInfo.service.IMesInfoService;
import com.ruoyi.projetctCost.ThreadPool.InstallationCostSummaryThreadPool;
import com.ruoyi.projetctCost.ThreadPool.SingletonThreadPool;
import com.ruoyi.projetctCost.beenfactory.ServiceBeenFactory;
import com.ruoyi.projetctCost.run.InstallationCostSummaryCallable;
import com.ruoyi.projetctCost.run.projectCostSummaryRunnable;
import com.ruoyi.projetctCost.util.RedisLockMethodUtil;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;


@Component("projectCostTask")
public class projectCostTask {
    public projectCostTask() {
    }

    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) {
        System.out.println(StringUtils.format("执行多参方法： 字符串类型{}，布尔类型{}，长整型{}，浮点型{}，整形{}", s, b, l, d, i));
    }

    public void ryParams(String params) {
        System.out.println("执行有参方法：" + params);
    }

    public void ryNoParams() {
        System.out.println("执行无参方法");
    }

    @Autowired
    private IKyTaskInfoService kyTaskInfoService;

    @Autowired
    private ServiceBeenFactory serviceBeenFactory;
    @Resource
    private RedisCache redisCache;

    /*计算项目成本的各组成部分，不包含装机成本，装机成本是增量计算的数据*/
    public void projectCostSummaryTask() {

        /*单例固定大小线程池*/
        ThreadPoolExecutor executor = SingletonThreadPool.getInstance().getExecutor();
        //当前科研任务总数
        int taskCount = kyTaskInfoService.getTaskCount();
        //分片距离
        int waterMark = 1000;
        //完整的分片
        int splitNum = taskCount / waterMark;
        //余数
        int remainder = taskCount % waterMark;
        //多开一个线程处理余数
        if (remainder > 0) splitNum = splitNum + 1;

        for (int i = 0; i < splitNum; i++) {
            /*项目成本的计算，以科研任务作为维度，以任务号分片加入线程池任务*/
            executor.execute(new projectCostSummaryRunnable(i, serviceBeenFactory, redisCache));
        }
    }

    /*计算项目成本内的装机成本*/
    public void InstallationCostSummaryTask() throws ExecutionException, InterruptedException {
        try {
            /*mes装机信息卡service*/
            IMesInfoService mesInfoService = serviceBeenFactory.getMesInfoService();
            /*装机成本计算专用线程池*/
            ThreadPoolExecutor executor = InstallationCostSummaryThreadPool.getInstance().getExecutor();

            IMesInfoInstallationcostService installationcostService = serviceBeenFactory.getInstallationcostService();

            List<MesInfoInstallationcost> mesInfoInstallationcosts = installationcostService.selectMesInfoInstallationcostList(new MesInfoInstallationcost());

            HashMap<String, HashMap<String, Object>> putCacheMap = new HashMap<>();
            for (MesInfoInstallationcost mesInfoInstallationcost : mesInfoInstallationcosts) {
                HashMap<String, Object> value = new HashMap<>();
                value.put(CacheConstants.VALUE, mesInfoInstallationcost.getValue());
                putCacheMap.put(mesInfoInstallationcost.getTaskno(), value);
            }
            redisCache.setCacheMap(CacheConstants.INSTALLATION_COST, putCacheMap);

            //一次while循环处理的数量
            long size = 10000;

            // 一个线程一次性处理2000条数据
            long watermark = 2000;

            while (true) {
                //获取当前mesInfo表中最大的主键
                Long MesInfoCount = mesInfoService.getMesInfoMaxKeyId();
                //获取上次处理的装机信息卡最后一条数据的id
                Long checkPoint = mesInfoService.selectCheckPoint();
                //未处理的数量
                long unprocessedQuantity = MesInfoCount - checkPoint;
                //未处理的数据为0，结束计算
                if (unprocessedQuantity == 0) {
                    break;
                }
                //未处理的数据量超过一万条，将其中一万条作为一个批次处理
                if (unprocessedQuantity < 100000) size = unprocessedQuantity;

                //起始id
                long startId = checkPoint; //0
                //终点ID
                long endId;
                //完整分片
                long splitNum = size / watermark;
                //余数
                long remainder = size % watermark;
                //有余数，就多开个线程处理
                if (remainder != 0) splitNum = splitNum + 1;

                ArrayList<Future<Boolean>> futures = new ArrayList<>();

                for (long i = 0; i < splitNum; i++) {
                    startId = startId + (size * i); // 0 2000
                    endId = startId + watermark + 1; //2001 4001
                    Future<Boolean> future = executor.submit(new InstallationCostSummaryCallable(startId, endId, serviceBeenFactory, RedisLockMethodUtil.getInstance(), redisCache));
                    futures.add(future);
                }
                boolean success = true;
                for (Future<Boolean> future : futures) {
                    Boolean aBoolean = future.get();
                    if (!aBoolean) {
                        success = aBoolean;
                    }
                }
                if (!success) {
                    break;
                }

                Map<String, Object> cacheMap = redisCache.getCacheMap(CacheConstants.INSTALLATION_COST);
                MesInfoInstallationcost installationcost;

                ArrayList<MesInfoInstallationcost> costs = new ArrayList<>();
                Set<Map.Entry<String, Object>> entries = cacheMap.entrySet();
                for (Map.Entry<String, Object> entry : entries) {
                    Object value = entry.getValue();
                    Map<String, Object> map = JSON.parseObject(JSON.toJSONString(value), new TypeReference<Map<String, Object>>() {
                    });
                    installationcost = new MesInfoInstallationcost();
                    installationcost.setTaskno(entry.getKey());
                    BigDecimal cacheValue = (BigDecimal) map.get(CacheConstants.VALUE);
                    installationcost.setValue(cacheValue);
                    costs.add(installationcost);
                }

                installationcostService.insertOrUpdateBatchMesInfoInstallationcost(costs);

                long newCheckPoint = checkPoint + size;
                int i = mesInfoService.recordCheckPoint(newCheckPoint);
                if (i == 0) break;
            }

        } finally {
            redisCache.deleteObject(CacheConstants.INSTALLATION_COST);
        }

    }
}
