package com.zcxk.charge.xxl.service;

import com.zcxk.charge.core.dao.MonitorDataMapper;
import com.zcxk.charge.core.entity.DayReportEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 报表业务处理
 * @author lihui
 * @version V1.0
 * @date 2021/5/18
 **/
@Component
@Slf4j
public class MonitorReportService {

    @Resource
    private MongoTemplate mongoTemplate;

    @Resource
    private MonitorDataMapper monitorDataMapper;

    /***
     * 数据补充
     * @Author lihui
     * @Date 9:55 2021/5/18
     * @param dateTime :   时间
     * @param lastHourDataMap : 上一个小时的数据
     * @return void
     **/
    public void replenishHistoryData(LocalDateTime dateTime, Map<String, DayReportEntity> lastHourDataMap){
        List<Integer> deviceIds = null;
        List<DayReportEntity> hourData = null;
        List<DayReportEntity> lastHourData = null;
        int total = 1;
        // 最多向前补一个月的数据
        int maxHour = 24 * 30;
        while (true) {
            if (total >= maxHour) {
                break;
            }
            dateTime = dateTime.plusHours(-1);
            // 设备id
            deviceIds = lastHourDataMap.values().stream().map(d -> d.getDeviceId().intValue()).distinct().collect(Collectors.toList());
            if (deviceIds.size() ==0) {
                break;
            }
            // 前1小时有统计数据的设备id
            List<Integer> deviceIdsIsExit = monitorDataMapper.checkReportDataExit(dateTime.getYear(),dateTime.getMonthValue(),dateTime.getDayOfMonth(),
                    dateTime.getHour(),deviceIds);
            // 需要补充数据的设备
            deviceIds = deviceIds.stream().filter(deviceId -> !deviceIdsIsExit.contains(deviceId)).collect(Collectors.toList());
            if (deviceIds.size() == 0) {
                break;
            }
            // 查询需要补充数据的设备数据信息
            hourData = lastHourDataMap.values().stream().filter(d -> !deviceIdsIsExit.contains(d.getDeviceId().intValue())).collect(Collectors.toList());
            lastHourData   = getMonitorDataGroupByHour(dateTime.plusHours(-1), deviceIds);
            lastHourDataMap = lastHourData.stream().collect(Collectors.toMap(DayReportEntity::getMapkey, a -> a, (k1, k2) -> k1));
            // 保存日报表数据
            saveReportDataByHour(hourData, lastHourDataMap);
            total++;
        }

    }

    /***
     * 数据保存
     * @Author lihui
     * @Date 9:55 2021/5/18
     * @param hourData :
     * @param lastHourDataMap :
     * @return void
     **/
    public void saveReportDataByHour(List<DayReportEntity> hourData, Map<String, DayReportEntity> lastHourDataMap) {
        if (hourData.size() == 0) {
            return;
        }
        DayReportEntity lastDayReportEntity = null;
        // 计算累计值
        for (DayReportEntity dayReportEntity : hourData) {
            if (dayReportEntity.getLatestValue() != null && lastHourDataMap.containsKey(dayReportEntity.getMapkey())) {
                lastDayReportEntity = lastHourDataMap.get(dayReportEntity.getMapkey());
                // 上一个小时有值
                if (lastDayReportEntity.getLatestValue() != null) {
                    dayReportEntity.setSumValue(new BigDecimal(dayReportEntity.getLatestValue().toString()).subtract(new BigDecimal(lastHourDataMap.get(dayReportEntity.getMapkey()).getLatestValue().toString())).doubleValue());
                } else {
                    // 上一个小时没有值,取本小时的初始值
                    if (dayReportEntity.getFirstValue() != null) {
                        dayReportEntity.setSumValue(new BigDecimal(dayReportEntity.getLatestValue().toString()).subtract(new BigDecimal(dayReportEntity.getFirstValue().toString())).doubleValue());
                    }
                    lastHourDataMap.remove(dayReportEntity.getMapkey());
                }
            }
            // 对平均值小数位处理
            dayReportEntity.setAvgValue(new BigDecimal(dayReportEntity.getAvgValue()).setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        monitorDataMapper.batchInsertDayReport(hourData);
    }

    /**
    * 查找报表
    * @author Andy
    * @date 11:27 2021/8/18
    * @param dateTime:
    * @param deviceIds:
    * @return java.util.List<com.zcxk.charge.core.entity.DayReportEntity>
    **/
    public List<DayReportEntity> getMonitorDataGroupByHour(LocalDateTime dateTime ,List<Integer> deviceIds ){
        if (dateTime == null ){
            return null;
        }
        Criteria criteria = new Criteria();
        criteria.and("year").is(dateTime.getYear());
        criteria.and("month").is(dateTime.getMonthValue());
        criteria.and("day").is(dateTime.getDayOfMonth());
        criteria.and("hour").is(dateTime.getHour());
        if(deviceIds!=null && deviceIds.size() > 0){
            criteria.and("deviceId").in(deviceIds);
        }
        AggregationOptions aggregationOptions = AggregationOptions.builder().allowDiskUse(true).build();
        Aggregation agg = Aggregation.newAggregation(
                // 查询条件
                Aggregation.match(criteria),
                // 将文档中的某一个数组类型字段拆分成多条，每条包含数组中的一个值
                Aggregation.unwind("dataValues"),
                // 在聚合之前对数据进行排序
                Aggregation.sort(Sort.Direction.ASC, "collectDate"),
                Aggregation.group("year","month","day","hour","tenantId","deviceId","deviceName",
                        "deviceCode","dataValues.attributeId","dataValues.attributeName" )
                        .min("$dataValues.dataValue").as("minValue")
                        .max("$dataValues.dataValue").as("maxValue")
                        .avg("$dataValues.dataValue").as("avgValue")
//                        .sum("$dataValues.dataValue").as("sumValue")
                        .first("$dataValues.dataValue").as("firstValue")
                        .last("$dataValues.dataValue").as("latestValue")
                        .last("$collectDate").as("collectDate")
                        .count().as("countNum")
        ).withOptions(aggregationOptions);
        AggregationResults<DayReportEntity> durationData =
                mongoTemplate.aggregate(agg, "SMS_MONITOR_DATA", DayReportEntity.class);
        return durationData.getMappedResults();
    }


}
