package com.tofly.scada.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tofly.scada.common.FlowConstant;
import com.tofly.scada.entity.*;
import com.tofly.scada.entity.dto.ScadaMoreQuery;
import com.tofly.scada.entity.dto.ScadaQuery;
import com.tofly.scada.entity.vo.ScadaDeviceCodeVo;
import com.tofly.scada.entity.vo.ScadaVo;
import com.tofly.scada.entity.vo.StatisticsScadaVo;
import com.tofly.scada.mapper.AllocationMapper;
import com.tofly.scada.mapper.ScadaReportMapper;
import com.tofly.scada.mapper.StatisticsScadaMapper;
import com.tofly.scada.service.ScadaMonitorService;
import com.tofly.scada.service.ScadaService;
import com.tofly.scada.service.StatisticsScadaService;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author haiqiu
 * @description 针对表【STATISTICS_SCADA】的数据库操作Service实现
 * @createDate 2022-05-10 15:55:35
 */
@Service
public class StatisticsScadaServiceImpl extends ServiceImpl<StatisticsScadaMapper, StatisticsScada> implements StatisticsScadaService {
    private final Logger logger = LoggerFactory.getLogger(StatisticsScadaServiceImpl.class);

    @Autowired
    private AllocationMapper allocationMapper;

    @Autowired
    private ScadaReportMapper reportMapper;

    @Autowired
    private ScadaMonitorService scadaMonitorService;

    @Autowired
    @Lazy
    private ScadaServiceImpl scadaService;

//    /**
//     * 根据开始结束时间获取月份表集合
//     * @param start 开始时间
//     * @param end 结束时间
//     * @return 月份表集合
//     */
//    public List<String> getMouthTables(Date start, Date end) {
//        List<Date> dates = ScadaServiceImpl.findDates(start, end, 1);
//        if (!CollectionUtils.isEmpty(dates)) {
//            List<String> tables = new ArrayList<>();
//            for (Date date : dates) {
//                //存储到分表月份
//                String tableName = scadaService.createMonths(date == null ? new Date() : date);
//                tables.add(tableName);
//            }
//            return tables;
//        }
//        return null;
//    }

    @Override
    public Page<StatisticsScadaVo> getPageData(Page page, ScadaQuery scadaQuery, Boolean isPage) {
        if (scadaQuery.getIsStatisticsScada() == null) {
            scadaQuery.setIsStatisticsScada(false);
        }
        //isGeTrendData 是否为趋势分析查询条件,主要是更换查询条件，此处主要是更换表查询 SCADA_HISTORY  STATISTICS_SCADA
        QueryWrapper<ScadaQuery> queryWrapper = getQuery(scadaQuery, scadaQuery.getIsStatisticsScada());
        if (scadaQuery.getIsStatisticsScada()){
            return baseMapper.pageList(page, queryWrapper,"STATISTICS_SCADA");
        }else {
            if (isPage==null){
                isPage = true;
            }
//            List<String> da = new ArrayList<>();
//            da.add("SCADA_HISTORY");
            return scadaService.selectHistoryByMouthsTables("SCADA_HISTORY",page,scadaQuery,isPage);
        }
//        scadaService.selectHistoryByMouthsTables(getMouthTables(scadaQuery.getStart(),scadaQuery.getEnd()),page,queryWrapper);
//        return baseMapper.pageList(page, queryWrapper, scadaQuery.getIsStatisticsScada() ? "STATISTICS_SCADA" : "SCADA_HISTORY");
    }

//    @Override
//    public List<StatisticsScadaVo> getDataList(ScadaQuery scadaQuery) {
//        if (scadaQuery.getIsStatisticsScada()==null){
//            scadaQuery.setIsStatisticsScada(false);
//        }
//        //isGeTrendData 是否为趋势分析查询条件,主要是更换查询条件，此处主要是更换表查询 SCADA_HISTORY  STATISTICS_SCADA
//        QueryWrapper<ScadaQuery> queryWrapper = getQuery(scadaQuery,scadaQuery.getIsStatisticsScada());
//        return baseMapper.list(queryWrapper,scadaQuery.getIsStatisticsScada() ? "STATISTICS_SCADA" : "SCADA_HISTORY");
//    }

    @Override
    public Page geTrendData(Page page, ScadaQuery scadaQuery, Boolean isPage) {
        QueryWrapper<ScadaQuery> queryWrapper = getQuery(scadaQuery, false);
        if (isPage) {
            Page<ScadaVo> scadaHistory = baseMapper.pageListNotStatistics(page, queryWrapper, "SCADA_HISTORY");
//            Page<ScadaVo> scadaHistory = baseMapper.selectHistoryByMouthsTables(getMouthTables(scadaQuery.getStart(),
//                    scadaQuery.getEnd()), page, queryWrapper);
            scadaValueHandle(scadaHistory.getRecords());
            return scadaHistory;
        } else {
            List<ScadaVo> scadaHistory = baseMapper.selectListDataNotStatistics(queryWrapper, "SCADA_HISTORY");
//            List<ScadaVo> scadaHistory = baseMapper.selectHistoryByMouthsTablesNoPage(getMouthTables(scadaQuery.getStart(),
//                    scadaQuery.getEnd()), queryWrapper);
            scadaValueHandle(scadaHistory);
            Page<StatisticsScadaVo> voPage = new Page<>();
            voPage.setRecords(calculationScadaData(scadaHistory, scadaQuery.getTimeTotal(), scadaQuery.getStart(), scadaQuery.getEnd()));
            return voPage;
        }
    }

    /**
     * 特殊值处理
     * @param scadaHistory
     */
    private void scadaValueHandle(List<ScadaVo> scadaHistory) {
        //特殊值处理
        for (ScadaVo scadaVo : scadaHistory) {
            if (scadaVo.getValue().startsWith(".")) {
                String value = scadaVo.getValue();
                scadaVo.setValue("0" + value);
            }
        }
    }

    @Override
    public int delete(Integer dateType, List<String> codes, Date start, Date end) {
        return baseMapper.deleteByTime(dateType, codes, start, end);
    }


    private List<StatisticsScadaVo> calculationScadaData(List<ScadaVo> scadaHistory, Integer excess, Date start, Date end) {
        //有数据就分组
        if (!CollectionUtils.isEmpty(scadaHistory)) {
            Map<String, List<ScadaVo>> listMap = scadaHistory.stream().filter(scada -> scada.getCode() != null && scada.getValue() != null)
                    .collect(Collectors.groupingBy(ScadaVo::getCode));

            List<StatisticsScadaVo> statisticsScadaVos = new ArrayList<>();
            for (Map.Entry<String, List<ScadaVo>> entity : listMap.entrySet()) {
                StatisticsScadaVo statisticsScadaVo = new StatisticsScadaVo();
                logger.info("有数据分组计算相关....");
                List<ScadaVo> scadaList = entity.getValue();
                double average = scadaList.stream().map(scada -> Double.parseDouble(scada.getValue()))
                        .mapToDouble(Double::shortValue).average().getAsDouble();
                double max = scadaList.stream().map(scada -> Double.parseDouble(scada.getValue()))
                        .mapToDouble(Double::shortValue).max().getAsDouble();
                double min = scadaList.stream().map(scada -> Double.parseDouble(scada.getValue()))
                        .mapToDouble(Double::shortValue).min().getAsDouble();
                double sum = scadaList.stream().map(scada -> Double.parseDouble(scada.getValue()))
                        .mapToDouble(Double::shortValue).sum();

                statisticsScadaVo.setCode(scadaList.get(0).getCode());
                statisticsScadaVo.setValue(scadaList.get(scadaList.size() - 1).getValue());
                statisticsScadaVo.setAve(average);
                statisticsScadaVo.setMax(max);
                statisticsScadaVo.setMin(min);
                statisticsScadaVo.setFold(sum);
                statisticsScadaVo.setStartTime(start);
                statisticsScadaVo.setEndTime(end);
                statisticsScadaVo.setStatisticsType(null);
                //设置分组子数据
                statisticsScadaVo.setScadaVos(scadaList);

                //查询指标报警上下限计算合格率相关
                logger.info("查询指标报警上下限计算合格率相关....");
                QueryWrapper<Allocation> allocationQueryWrapper = new QueryWrapper<>();
                allocationQueryWrapper.eq("VARIABLE_CODE", scadaList.get(0).getCode());
                List<Allocation> allocations = allocationMapper.selectList(allocationQueryWrapper);
                if (!CollectionUtils.isEmpty(allocations)) {
                    Set<Long> reportIdSets = ScadaServiceImpl.getReportIdSets(allocations);
                    logger.info("获取模版ID集合：{}....", reportIdSets);
                    if (!CollectionUtils.isEmpty(reportIdSets)) {
                        logger.info("计算指标报警上下限计算合格率相关....");
                        QueryWrapper<ScadaReport> scadaReportQueryWrapper = new QueryWrapper<>();
                        scadaReportQueryWrapper.in("ID", reportIdSets);
                        List<ScadaReport> scadaReports = reportMapper.selectList(scadaReportQueryWrapper);
                        if (!CollectionUtils.isEmpty(scadaReports)) {
                            //赋值报警列表
                            statisticsScadaVo.setScadaReports(scadaReports);
                            //超标次数
                            int errorCount = 0;
                            //不合格超标时长
                            long errorTimeTotal = 0;
                            //超标总时长
//                            long timeTotal = (scadaList.get(scadaList.size() - 1).getScadaTime().getTime()
//                                    - scadaList.get(0).getScadaTime().getTime()) / 1000;
                            //错误时间
                            Date errorTime;
                            for (ScadaVo scada : scadaList) {
                                for (ScadaReport report : scadaReports) {
                                    if (scada.getValue() == null){
                                        break;
                                    } else if(report.getReportLower() == null || report.getReportUpper() == null) {
                                        continue;
                                    }
                                    if (Double.parseDouble(scada.getValue()) > Double.parseDouble(report.getReportLower())
                                            && Double.parseDouble(scada.getValue()) < Double.parseDouble(report.getReportUpper())) {
                                        errorCount ++;
                                        errorTime = scada.getScadaTime();
                                        if(errorTime != null){
                                            errorTimeTotal += errorTime.getTime() / 1000;
                                        }
                                        break;
                                    }
                                }
                            }
                            //合格率
                            long totalCount = scadaList.size();
                            float pass = 100.00f;
                            if(totalCount != 0 && errorCount != 0){
                                long passCount = totalCount - errorCount;
                                pass = new BigDecimal(passCount).divide(BigDecimal.valueOf(totalCount),4,RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).floatValue();
                            }
                            statisticsScadaVo.setErrorCount(errorCount);
                            statisticsScadaVo.setErrorTimeTotal(errorTimeTotal);
                            statisticsScadaVo.setPass(pass);
                            statisticsScadaVo.setTimeTotal(errorTimeTotal);
                        }
                    }
                    statisticsScadaVo.setDisplayName(allocations.get(0).getDisplayName());
                    statisticsScadaVo.setDataType(String.valueOf(allocations.get(0).getType()));
                }
                //TODO 暂时全部返回，后续调整
//                if (excess != null && statisticsScadaVo.getErrorTimeTotal()!=null && statisticsScadaVo.getErrorTimeTotal() >= excess) {
//                    statisticsScadaVos.add(statisticsScadaVo);
//                } else if (excess == null) {
                statisticsScadaVos.add(statisticsScadaVo);
//                }
            }
            return statisticsScadaVos;
        }
        return null;
    }


    /**
     * 构建查询条件
     *
     * @param scadaQuery    查询实体
     * @param isGeTrendData 是否为趋势分析查询条件
     * @return
     */
    public QueryWrapper<ScadaQuery> getQuery(ScadaQuery scadaQuery, Boolean isGeTrendData) {
        QueryWrapper<ScadaQuery> queryWrapper = new QueryWrapper<>();
        if (!CollectionUtils.isEmpty(scadaQuery.getCodes())) {
            queryWrapper.in("scada.CODE", scadaQuery.getCodes());
        }
        if (!StringUtils.isEmpty(scadaQuery.getCode())) {
            queryWrapper.eq("scada.CODE", scadaQuery.getCode());
        }
        if (!CollectionUtils.isEmpty(scadaQuery.getDeviceIds())) {
            queryWrapper.in("manage.ID", scadaQuery.getDeviceIds());
        }
        if (scadaQuery.getDataTypeIds() != null) {
            Set<String> typeIds = scadaQuery.getDataTypeIds().stream().filter(Objects::nonNull)
                    .map(String::valueOf).collect(Collectors.toSet());
            queryWrapper.in("allocation.TYPE", typeIds);
        }
        if (scadaQuery.getStart() != null && scadaQuery.getEnd() != null) {
            if (scadaQuery.getStart().getTime() > scadaQuery.getEnd().getTime()) {
                throw new RuntimeException("开始时间不能大于结束时间");
            }
            if (isGeTrendData) {
                if (scadaQuery.getStatisticsType() != null) {
                    queryWrapper.eq("scada.STATISTICS_TYPE", scadaQuery.getStatisticsType());
                }
                queryWrapper.ge("scada.START_TIME", scadaQuery.getStart())
                        .le("scada.END_TIME", scadaQuery.getEnd());
                queryWrapper.orderByAsc("scada.START_TIME");
            } else {
                queryWrapper.between("scada.SCADA_TIME", scadaQuery.getStart(), scadaQuery.getEnd());
//                queryWrapper.orderByAsc("scada.SCADA_TIME");
            }
        }
        //如果是趋势分析查询
        if (isGeTrendData) {
            if (scadaQuery.getStart() == null && scadaQuery.getEnd() == null) {
                throw new RuntimeException("该接口时间范围为必填项");
            }
            //如果没有传入code就默认查询全部
            if (!StringUtils.hasText(scadaQuery.getCode()) && CollectionUtils.isEmpty(scadaQuery.getCodes())) {
                List<Allocation> allocations = allocationMapper.selectList(null);
                if (!CollectionUtils.isEmpty(allocations)) {
                    Set<String> codes = allocations.stream().filter(allocation -> allocation.getVariableCode() != null)
                            .map(Allocation::getVariableCode).collect(Collectors.toSet());
                    queryWrapper.in("scada.CODE", codes);
                }
            }
        }

        return queryWrapper;
    }

//    /**
//     * 获取指标报警的最低等级下限和最高等级上限
//     * @param scadaReportList 报警信息列表
//     * @return
//     */
//    private Map<String,Double> getReportUpperLower(List<ScadaReport> scadaReportList){
//        if(scadaReportList == null || scadaReportList.size() == 0){
//            return null;
//        }
//        Map<String,Double> res = new HashMap<>();
//        Double reportLower = null;
//        Double reportUpper = null;
//        double mid;
//        for (ScadaReport scadaReport : scadaReportList) {
//            if(scadaReport.getReportUpper() != null && scadaReport.getReportLower() != null){
//                if(reportLower == null){
//                    reportLower = Double.parseDouble(String.valueOf(scadaReport.getReportLower()));
//                }else {
//                    mid = Double.parseDouble(String.valueOf(scadaReport.getReportLower()));
//                    if(reportLower.compareTo(mid) > 0){
//                        reportLower = mid;
//                    }
//                }
//                if(reportUpper == null){
//                    reportUpper = Double.parseDouble(String.valueOf(scadaReport.getReportUpper()));
//                }else {
//                    mid = Double.parseDouble(String.valueOf(scadaReport.getReportUpper()));
//                    if(reportUpper.compareTo(mid) < 0){
//                        reportUpper = mid;
//                    }
//                }
//            }
//        }
//        if(reportLower == null || reportUpper == null){
//            return null;
//        }
//        res.put("reportLower",reportLower);
//        res.put("reportUpper",reportUpper);
//        return res;
//    }

    @Transactional(rollbackFor = Exception.class)
    public void insertBacthHistoryTemp(ScadaMoreQuery scadaMoreQuery) {
        if (scadaMoreQuery == null) {
            return;
        }
        List<Scada> historyTempList = scadaMoreQuery.getHistoryTempList();
        if (CollUtil.isEmpty(historyTempList)) {
            return;
        }
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                12,
                24,
                120,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(200),
                (r)->{
                    Thread t = new Thread(r);
                    t.setName("thread-" + ((int)(Math.random()*1000)));
                    return t;},
                new ThreadPoolExecutor.CallerRunsPolicy());
        //为了防止SQL语句超出长度出错，分成几次插入
        if (historyTempList.size() <= 2000) {
            threadPoolExecutor.execute(() -> baseMapper.insertBacthHistoryTemp(historyTempList));
        } else {
            int times = historyTempList.size() / 2000;
            for (int i = 0; i <= times; i++) {
                int finalI = i;
                threadPoolExecutor.execute(() ->  baseMapper.insertBacthHistoryTemp(historyTempList.subList(finalI * 2000, Math.min((finalI + 1) * 2000, historyTempList.size()))));
            }
        }
        logger.info("新增scada历史数据完成");
    }

//    /**
//     * 每两分钟同步实时数据
//     *
//     */
//    @Async
//    @Scheduled(cron = "0 0/2 * * * ? ")
//    @SneakyThrows
//    public void syncMonitorData(){
//        Calendar calendar = Calendar.getInstance();
//        Date endTime = calendar.getTime();
//        calendar.add(Calendar.MINUTE, -3);
//        calendar.set(Calendar.SECOND, 0);
//        Date startTime = calendar.getTime();
//        updateMonitor(startTime, endTime);
//    }
//
//    private void updateMonitor(Date startTime, Date endTime) {
//        List<Scada> scadaHistoryList = baseMapper.selectScadaHistoryList(DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
//        scadaHistoryList = scadaHistoryList.stream().sorted(Comparator.comparing(Scada::getScadaTime).reversed()).collect(Collectors.toList());
//        TreeSet<Scada> treeSet = new TreeSet<>((o1, o2) -> {
//            String key1 = o1.getCode();
//            String key2 = o2.getCode();
//            return key1.compareTo(key2);
//        });
//        treeSet.addAll(scadaHistoryList);
//        List<Scada> monitorList = new ArrayList<>(treeSet);
//        //为了防止SQL语句超出长度出错，分成几次插入
//        if (monitorList.size() <= 2000) {
//            baseMapper.updateRealBatchTemp(monitorList);
//        } else {
//            int times = monitorList.size() / 2000;
//            for (int i = 0; i <= times; i++) {
//                baseMapper.updateRealBatchTemp(monitorList.subList(i * 2000, Math.min((i + 1) * 2000, monitorList.size())));
//            }
//        }
//        logger.info("*************每两分钟更新实时数据成功！*****************");
//    }

//    /**
//     * 更新异常点位实时数据
//     *
//     */
//    @Async
//    @Scheduled(cron = "0 0 0/6 * * ? ")
//    @SneakyThrows
//    public void syncAbnormalPointData(){
//        Calendar calendar = Calendar.getInstance();
//        calendar.set(Calendar.MINUTE, 0);
//        calendar.add(Calendar.MINUTE, -1);
//        calendar.set(Calendar.SECOND, 59);
//        Date endTime = calendar.getTime();
//        calendar.add(Calendar.MINUTE, +1);
//        calendar.add(Calendar.HOUR, -6);
//        calendar.set(Calendar.SECOND, 0);
//        Date startTime = calendar.getTime();
//        List<Scada> scadaHistoryList = baseMapper.selectScadaHistoryList(DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
//        Calendar last = Calendar.getInstance();
//        last.set(Calendar.MINUTE, 0);
//        last.add(Calendar.HOUR, -6);
//        last.add(Calendar.MINUTE, -1);
//        last.set(Calendar.SECOND, 59);
//        Date endTimeLast = calendar.getTime();
//        last.add(Calendar.MINUTE, +1);
//        last.add(Calendar.HOUR, -6);
//        last.set(Calendar.SECOND, 0);
//        Date startTimeLast = calendar.getTime();
//        List<Scada> scadaHistoryListLast = baseMapper.selectScadaHistoryList(DateUtil.format(startTimeLast, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTimeLast, "yyyy-MM-dd HH:mm:ss"));
//
//        List<Map<String, Object>> codes = baseMapper.getAbnormalPointIndexList();
//        List<Date> dates = getFiveIntervalDates(startTime, endTime);
//        List<Scada> monitorList = new ArrayList<>();
//        codes.forEach(info -> {
//            if (String.valueOf(info.get("type")).equals("13")) {
//                for (Date date : dates) {
//                    Scada scada = new Scada();
//                    scada.setCode(String.valueOf(info.get("code")));
//                    Random rand = new Random();
//                    int randomNum = rand.nextInt(800 - 600 + 1) + 600;
//                    scada.setValue(String.valueOf(randomNum));
//                    scada.setScadaTime(date);
//                    scada.setUpdateTime(new Date());
//                    monitorList.add(scada);
//                }
//            }
//            if (String.valueOf(info.get("type")).equals("17")
//                    || String.valueOf(info.get("type")).equals("18")
//                    || String.valueOf(info.get("type")).equals("19")) {
//                long value = 1079674L;
//                List<Scada> scadaHistoryListLastF = scadaHistoryListLast.stream().filter(e -> e.getCode().equals(info.get("code"))).collect(Collectors.toList());
//                if (CollUtil.isNotEmpty(scadaHistoryListLastF)) {
//                    Scada one = scadaHistoryListLastF.get(0);
//                    value = Long.parseLong(one.getValue());
//                }
//                for (Date date : dates) {
//                    Scada scada = new Scada();
//                    scada.setCode(String.valueOf(info.get("code")));
//                    Random rand = new Random();
//                    long randomNum = rand.nextInt(100 + 1);
//                    value = value + randomNum;
//                    scada.setValue(String.valueOf(value));
//                    scada.setScadaTime(date);
//                    scada.setUpdateTime(new Date());
//                    monitorList.add(scada);
//                }
//            }
//        });
//
//        if (CollUtil.isEmpty(monitorList)) {
//            return;
//        }
//        scada1Service.remove(new QueryWrapper<Scada>().in("ID",scadaHistoryList.stream().map(Scada::getId).collect(Collectors.toList())));
//        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
//                8,
//                16,
//                120,
//                TimeUnit.SECONDS,
//                new ArrayBlockingQueue<>(500),
//                (r)->{
//                    Thread t = new Thread(r);
//                    t.setName("thread-" + ((int)(Math.random()*1000)));
//                    return t;},
//                new ThreadPoolExecutor.CallerRunsPolicy());
//        //为了防止SQL语句超出长度出错，分成几次插入
//        if (monitorList.size() <= 2000) {
//            threadPoolExecutor.execute(() -> baseMapper.insertBacthHistoryTemp(monitorList));
//        } else {
//            int times = monitorList.size() / 2000;
//            for (int i = 0; i <= times; i++) {
//                List<Scada> finalList = monitorList.subList(i * 2000, Math.min((i + 1) * 2000, monitorList.size()));
//                if (CollUtil.isEmpty(finalList)) {
//                    continue;
//                }
//                threadPoolExecutor.execute(() ->  baseMapper.insertBacthHistoryTemp(finalList));
//            }
//        }
//        logger.info("-----------------异常点位的指标数据新增scada历史数据完成------------------");
//    }

    /**
     * 更新异常点位实时数据
     *
     */
    @Async
    @Scheduled(cron = "0 10 0/1 * * ? ")
    @SneakyThrows
    public void timeAbnormalPointData() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR, -1);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        Date endTime = calendar.getTime();
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date startTime = calendar.getTime();
        syncAbnormalPointData(DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 更新异常点位实时数据
     *
     */
    @Override
    public void syncAbnormalPointData(String startDate, String endDate) {
        List<ScadaDeviceCodeVo> scadaHistoryList = baseMapper.selectScadaHistoryList(startDate, endDate);
        Map<String, List<ScadaDeviceCodeVo>> scadaHistoryListByCode = scadaHistoryList.stream().filter(e -> org.apache.commons.lang3.StringUtils.isNotEmpty(e.getDeviceCode())).collect(Collectors.groupingBy(ScadaDeviceCodeVo::getDeviceCode));

        List<Map<String, Object>> abnorCodes = baseMapper.getAbnormalPointIndexList();
        Map<String, List<Map<String, Object>>> abnorCodeListByDeviceCode = abnorCodes.stream().collect(Collectors.groupingBy(e -> String.valueOf(e.get("deviceCode"))));

        List<Scada> monitorList = new ArrayList<>();
        List<ScadaMonitor> realTimeList = new ArrayList<>();
        List<ScadaMonitor> finalRealTimeList = realTimeList;
        abnorCodeListByDeviceCode.forEach((k, v) -> {
            List<ScadaDeviceCodeVo> scadaDeviceCodeVos = null;
            BigDecimal multiplyNumber = BigDecimal.ZERO;
            switch (k) {
                case "FT_B_15":
                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_17");
                    multiplyNumber = BigDecimal.valueOf(0.21);
                    break;
                case "FT_A_3":
                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_19");
                    multiplyNumber = BigDecimal.valueOf(0.85).multiply(BigDecimal.valueOf(0.43));
                    break;
                case "FT_A_8":
                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos4 = scadaHistoryListByCode.get("FT_B_20");
                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos5 = scadaHistoryListByCode.get("FT_B_4");
                    if(CollectionUtils.isEmpty(scadaDeviceCodeVos4)){
                        return;
                    }
                    scadaDeviceCodeVos4.forEach(scadaDeviceCodeVo -> {
                        List<Map<String, Object>> indexCodes = v.stream().filter(e -> String.valueOf(e.get("type")).equals(scadaDeviceCodeVo.getIndexType())).collect(Collectors.toList());
                        if (CollUtil.isEmpty(indexCodes)) {
                            return;
                        }
                        List<ScadaDeviceCodeVo> scadaDeviceCodeVos5Final = scadaDeviceCodeVos5.stream()
                                .filter(e -> e.getIndexType().equals(scadaDeviceCodeVo.getIndexType())
                                        && DateUtil.format(e.getScadaTime(), "yyyyMMddHHmm").equals(DateUtil.format(scadaDeviceCodeVo.getScadaTime(), "yyyyMMddHHmm")))
                                .collect(Collectors.toList());
                        String indexCode = String.valueOf(indexCodes.get(0).get("indexCode"));
                        Scada scada = new Scada();
                        ScadaMonitor scadaMonitor = new ScadaMonitor();
                        scada.setCode(indexCode);
                        scadaMonitor.setCode(indexCode);
                        scada.setValue(new BigDecimal(scadaDeviceCodeVo.getValue())
                                .add(CollUtil.isEmpty(scadaDeviceCodeVos5Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos5Final.get(0).getValue()))
                                .multiply(BigDecimal.valueOf(1.6))
                                .multiply(BigDecimal.valueOf(0.35))
                                .setScale(2,RoundingMode.HALF_UP)
                                .toString());
                        scadaMonitor.setValue(new BigDecimal(scadaDeviceCodeVo.getValue())
                                .add(CollUtil.isEmpty(scadaDeviceCodeVos5Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos5Final.get(0).getValue()))
                                .multiply(BigDecimal.valueOf(1.6))
                                .multiply(BigDecimal.valueOf(0.35))
                                .setScale(2,RoundingMode.HALF_UP)
                                .toString());
                        scada.setScadaTime(scadaDeviceCodeVo.getScadaTime());
                        scadaMonitor.setScadaTime(scadaDeviceCodeVo.getScadaTime());
                        scada.setUpdateTime(new Date());
                        scadaMonitor.setUpdateTime(new Date());
                        monitorList.add(scada);
                        finalRealTimeList.add(scadaMonitor);
                    });
                    return;
                case "FT_A_9":
                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos1 = scadaHistoryListByCode.get("FT_B_22");
                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos2 = scadaHistoryListByCode.get("FT_A_6");
                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos3 = scadaHistoryListByCode.get("FT_A_7");
                    if(CollectionUtils.isEmpty(scadaDeviceCodeVos1)){
                        return;
                    }
                    scadaDeviceCodeVos1.forEach(scadaDeviceCodeVo -> {
                        List<Map<String, Object>> indexCodes = v.stream().filter(e -> String.valueOf(e.get("type")).equals(scadaDeviceCodeVo.getIndexType())).collect(Collectors.toList());
                        if (CollUtil.isEmpty(indexCodes)) {
                            return;
                        }
                        List<ScadaDeviceCodeVo> scadaDeviceCodeVos2Final = scadaDeviceCodeVos2.stream()
                                .filter(e -> e.getIndexType().equals(scadaDeviceCodeVo.getIndexType())
                                        && DateUtil.format(e.getScadaTime(), "yyyyMMddHHmm").equals(DateUtil.format(scadaDeviceCodeVo.getScadaTime(), "yyyyMMddHHmm")))
                                .collect(Collectors.toList());
                        List<ScadaDeviceCodeVo> scadaDeviceCodeVos3Final = scadaDeviceCodeVos3.stream()
                                .filter(e -> e.getIndexType().equals(scadaDeviceCodeVo.getIndexType())
                                        && DateUtil.format(e.getScadaTime(), "yyyyMMddHHmm").equals(DateUtil.format(scadaDeviceCodeVo.getScadaTime(), "yyyyMMddHHmm")))
                                .collect(Collectors.toList());
                        String indexCode = String.valueOf(indexCodes.get(0).get("indexCode"));
                        Scada scada = new Scada();
                        ScadaMonitor scadaMonitor = new ScadaMonitor();
                        scada.setCode(indexCode);
                        scadaMonitor.setCode(indexCode);
                        scada.setValue(new BigDecimal(scadaDeviceCodeVo.getValue())
                                .add(CollUtil.isEmpty(scadaDeviceCodeVos2Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos2Final.get(0).getValue()))
                                .add(CollUtil.isEmpty(scadaDeviceCodeVos3Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos3Final.get(0).getValue()))
                                .multiply(BigDecimal.valueOf(0.71))
                                .setScale(2,RoundingMode.HALF_UP)
                                .toString());
                        scadaMonitor.setValue(new BigDecimal(scadaDeviceCodeVo.getValue())
                                .add(CollUtil.isEmpty(scadaDeviceCodeVos2Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos2Final.get(0).getValue()))
                                .add(CollUtil.isEmpty(scadaDeviceCodeVos3Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos3Final.get(0).getValue()))
                                .multiply(BigDecimal.valueOf(0.71))
                                .setScale(2,RoundingMode.HALF_UP)
                                .toString());
                        scada.setScadaTime(scadaDeviceCodeVo.getScadaTime());
                        scadaMonitor.setScadaTime(scadaDeviceCodeVo.getScadaTime());
                        scada.setUpdateTime(new Date());
                        scadaMonitor.setUpdateTime(new Date());
                        monitorList.add(scada);
                        finalRealTimeList.add(scadaMonitor);
                    });
                    return;
                case "FT_A_10":
                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_6");
                    multiplyNumber = BigDecimal.valueOf(0.88);
                    break;
//                case "FT_A_12":
//                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_6");
//                    multiplyNumber = BigDecimal.valueOf(0.12).multiply(BigDecimal.valueOf(0.88)).multiply(BigDecimal.valueOf(0.88));
//                    break;
                case "FT_A_16":
                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_17");
                    multiplyNumber = BigDecimal.valueOf(0.72);
                    break;
//                case "FT_A_20":
//                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_19");
//                    multiplyNumber = BigDecimal.valueOf(0.43);
//                    break;
//                case "FT_A_21":
//                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_19");
//                    multiplyNumber = BigDecimal.valueOf(0.39);
//                    break;
//                case "FT_A_22":
//                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos6 = scadaHistoryListByCode.get("FT_B_20");
//                    List<ScadaDeviceCodeVo> scadaDeviceCodeVos7 = scadaHistoryListByCode.get("FT_B_4");
//                    scadaDeviceCodeVos6.forEach(scadaDeviceCodeVo -> {
//                        List<Map<String, Object>> indexCodes = v.stream().filter(e -> String.valueOf(e.get("type")).equals(scadaDeviceCodeVo.getIndexType())).collect(Collectors.toList());
//                        if (CollUtil.isEmpty(indexCodes)) {
//                            return;
//                        }
//                        List<ScadaDeviceCodeVo> scadaDeviceCodeVos7Final = scadaDeviceCodeVos7.stream()
//                                .filter(e -> e.getIndexType().equals(scadaDeviceCodeVo.getIndexType())
//                                        && DateUtil.format(e.getScadaTime(), "yyyyMMddHHmm").equals(DateUtil.format(scadaDeviceCodeVo.getScadaTime(), "yyyyMMddHHmm")))
//                                .collect(Collectors.toList());
//                        String indexCode = String.valueOf(indexCodes.get(0).get("indexCode"));
//                        Scada scada = new Scada();
//                        ScadaMonitor scadaMonitor = new ScadaMonitor();
//                        scada.setCode(indexCode);
//                        scadaMonitor.setCode(indexCode);
//                        scada.setValue(new BigDecimal(scadaDeviceCodeVo.getValue())
//                                .add(CollUtil.isEmpty(scadaDeviceCodeVos7Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos7Final.get(0).getValue()))
//                                .multiply(BigDecimal.valueOf(1.6))
//                                .setScale(2,RoundingMode.HALF_UP)
//                                .toString());
//                        scadaMonitor.setValue(new BigDecimal(scadaDeviceCodeVo.getValue())
//                                .add(CollUtil.isEmpty(scadaDeviceCodeVos7Final) ? BigDecimal.ZERO:new BigDecimal(scadaDeviceCodeVos7Final.get(0).getValue()))
//                                .multiply(BigDecimal.valueOf(1.6))
//                                .setScale(2,RoundingMode.HALF_UP)
//                                .toString());
//                        scada.setScadaTime(scadaDeviceCodeVo.getScadaTime());
//                        scadaMonitor.setScadaTime(scadaDeviceCodeVo.getScadaTime());
//                        scada.setUpdateTime(new Date());
//                        scadaMonitor.setUpdateTime(new Date());
//                        monitorList.add(scada);
//                        finalRealTimeList.add(scadaMonitor);
//                    });
//                    return;
                case "FT_A_24":
                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_19");
                    multiplyNumber = BigDecimal.valueOf(0.93).multiply(BigDecimal.valueOf(0.39));
                    break;
                case "FT_A_25":
                    scadaDeviceCodeVos = scadaHistoryListByCode.get("FT_A_6");
                    multiplyNumber = BigDecimal.valueOf(0.88).multiply(BigDecimal.valueOf(0.88));
                    break;
            }
            if (CollUtil.isEmpty(scadaDeviceCodeVos)) {
                return;
            }
            BigDecimal finalMultiplyNumber = multiplyNumber;
            if(CollectionUtils.isEmpty(scadaDeviceCodeVos)){
                return;
            }
            scadaDeviceCodeVos.forEach(scadaDeviceCodeVo -> {
                List<Map<String, Object>> indexCodes = v.stream().filter(e -> String.valueOf(e.get("type")).equals(scadaDeviceCodeVo.getIndexType())).collect(Collectors.toList());
                if (CollUtil.isEmpty(indexCodes)) {
                    return;
                }
                String indexCode = String.valueOf(indexCodes.get(0).get("indexCode"));
                Scada scada = new Scada();
                ScadaMonitor scadaMonitor = new ScadaMonitor();
                scada.setCode(indexCode);
                scadaMonitor.setCode(indexCode);
                scada.setValue(new BigDecimal(scadaDeviceCodeVo.getValue()).multiply(finalMultiplyNumber).setScale(2,RoundingMode.HALF_UP).toString());
                scadaMonitor.setValue(new BigDecimal(scadaDeviceCodeVo.getValue()).multiply(finalMultiplyNumber).setScale(2,RoundingMode.HALF_UP).toString());
                scada.setScadaTime(scadaDeviceCodeVo.getScadaTime());
                scadaMonitor.setScadaTime(scadaDeviceCodeVo.getScadaTime());
                scada.setUpdateTime(new Date());
                scadaMonitor.setUpdateTime(new Date());
                monitorList.add(scada);
                finalRealTimeList.add(scadaMonitor);
            });
        });
        if (CollUtil.isEmpty(monitorList)) {
            return;
        }
        scadaService.remove(new QueryWrapper<Scada>()
                        .between("to_char(scada_time, 'yyyy-mm-dd hh24:mi:ss')", startDate, endDate)
                        .in("code", abnorCodes.stream().map(e -> String.valueOf(e.get("indexCode"))).collect(Collectors.toList())));
        scadaService.saveBatch(monitorList);
        realTimeList.sort(Comparator.comparing(ScadaMonitor::getScadaTime).reversed());
        realTimeList = realTimeList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ScadaMonitor::getCode))), ArrayList::new));
        realTimeList.forEach(info -> scadaMonitorService.update(info, new QueryWrapper<ScadaMonitor>().lambda().eq(ScadaMonitor::getCode, info.getCode())));
    }
}
