package com.zcxk.service.impl;

import com.zcxk.dao.MonitorDataMapper;
import com.zcxk.entity.DayReportEntity;
import com.zcxk.entity.MonitorDataEntity;
import com.zcxk.quartz.entity.QuartzEntity;
import com.zcxk.quartz.job.MonitorDataReportByDayJob;
import com.zcxk.quartz.job.MonitorDataReportByMonthJob;
import com.zcxk.quartz.job.MonitorDataReportByYearJob;
import com.zcxk.quartz.service.JobAndTriggerService;
import com.zcxk.quartz.service.MonitorReportJobService;
import com.zcxk.service.MonitorDataService;
import com.zcxk.util.ByteArrayUtils;
import com.zcxk.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description
 * @author  wangli
 * @data 2020-12-01 11:09
 */
@Service
@Slf4j
public class MonitorDataServiceImpl implements MonitorDataService , InitializingBean {

    @Resource
    private MongoTemplate mongoTemplate;

    @Resource
    private MonitorDataMapper monitorDataMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private JobAndTriggerService jobAndTriggerService;

    @Autowired
    private MonitorReportJobService monitorReportJobServcie;

    @Override
    public void afterPropertiesSet() {
        saveQrtzTask("0 0 */1 * * ? ","日报生成任务","smsWaterMonitorDataReportByDayJob",MonitorDataReportByDayJob.class.getName());
        saveQrtzTask("0 5 0 * * ? ","月报报生成任务","smsWaterMonitorDataReportByMonthJob", MonitorDataReportByMonthJob.class.getName());
        saveQrtzTask("0 10 0 1 * ? ","年报生成任务","smsWaterMonitorDataReportByYearJob", MonitorDataReportByYearJob.class.getName());
    }

    /***
     * 1,查询需要批量推送的配置项目并构建定时任务
     * 2,若对应定时任务不存在则创建
     * @Author wangli
     * @param cron :
     * @param jobGroup :
     * @param jobName :
     * @param jobClassName :
     * @return void
     **/
    public void saveQrtzTask(String cron, String jobGroup ,String jobName,String jobClassName) {
        QuartzEntity entity = new QuartzEntity();
        entity.setJobGroup(jobGroup);
        entity.setJobName(jobName);
        entity.setDescription(jobName);
        boolean exists = jobAndTriggerService.isExists(entity);
        if(!exists){
            entity.setCronExpression(cron);
            entity.setJobClassName(jobClassName);
            jobAndTriggerService.save(entity);
        }
    }

    @Override
    public MonitorDataEntity save(MonitorDataEntity monitorDataEntity) {
        // 缓存数据
        redisUtil.setExpire(("sms_water_"+monitorDataEntity.getDeviceCode()).getBytes(), ByteArrayUtils.objectToBytes(monitorDataEntity).get());
        // 把没有数据的属性去掉再保存
        monitorDataEntity.setDataValues(monitorDataEntity.getDataValues().stream().filter(m -> m.getDataValue()!=null).collect(Collectors.toList()));

        return mongoTemplate.save(monitorDataEntity);
    }

    @Override
    public MonitorDataEntity getDeviceMonitorInfoByDeviceCode(String deviceCode){
        // 先取缓存里的数据
        byte[] bytes = redisUtil.get(("sms_water_"+deviceCode).getBytes());
        if(bytes != null && bytes.length>0){
            return (MonitorDataEntity)ByteArrayUtils.bytesToObject(bytes).get();
        }
        return monitorDataMapper.getDeviceMonitorInfoByDeviceCode(deviceCode);
    }

    @Override
    public void remove(Long id) {
        mongoTemplate.remove(id);
    }

    @Override
    public void update(MonitorDataEntity monitorDataEntity) {
        Query query = new Query(Criteria.where("id").is(monitorDataEntity.getId()));
        Update update = new Update();
        update.set("deviceName", monitorDataEntity.getDeviceName());
        mongoTemplate.updateFirst(query, update, MonitorDataEntity.class);
    }

    @Override
    public MonitorDataEntity findById(Long id) {
        Query query = new Query(Criteria.where("id").is(id));
        MonitorDataEntity monitorDataEntity = mongoTemplate.findOne(query, MonitorDataEntity.class);
        return monitorDataEntity;
    }

   @Override
    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();
    }

    /*@Override
    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);
        }
        BasicDBObject query = new BasicDBObject();
        query.put("year",dateTime.getYear());
        query.put("month",dateTime.getMonthValue());
        query.put("day",dateTime.getDayOfMonth());
        query.put("hour",dateTime.getHour());
        if (deviceIds != null && deviceIds.size() > 0) {
            query.put("deviceId",new BasicDBObject("$in", deviceIds));
        }
        FindIterable<Document> iter = mongoTemplate.getCollection("SMS_MONITOR_DATA").find(query, Document.class);
        iter.forEach(new Block<Document>() {
            @Override
            public void apply(Document entity) {
                System.out.println(entity.toJson());
            }
        });
        return null;
    }*/


    @Override
    public void getMonitorDataReportByHour(){
        // 取前一个小时的时间
        LocalDateTime dateTime = LocalDateTime.now().plusHours(-1);
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // dateTime = LocalDateTime.parse("2021-05-29 11:00:00", fmt);
        // 取前一个小时的时间(取19点) sumValue  -> 1-10,2-20
        List<DayReportEntity> hourData     = getMonitorDataGroupByHour(dateTime,null);
        // 取前一个小时的时间(取18点)
        List<DayReportEntity> lastHourData = getMonitorDataGroupByHour(dateTime.plusHours(-1),null);
        Map<String,DayReportEntity> lastHourDataMap = lastHourData.stream().collect(Collectors.toMap(DayReportEntity::getMapkey, a -> a,(k1, k2)->k1));
        // 保存日报表数据
        monitorReportJobServcie.saveReportDataByHour(hourData, lastHourDataMap);
        if (lastHourDataMap.values().size() == 0){
            return;
        }
        // 补充数据
        monitorReportJobServcie.replenishHistoryData(dateTime, lastHourDataMap);
    }

    @Override
    public void getMonitorDataByDay() {
        //取前一天的时间
        LocalDateTime dateTime = LocalDateTime.now().plusDays(-1);
        //保存日报表数据
        monitorDataMapper.batchInsertMonthReport(dateTime.getYear(),dateTime.getMonthValue(),dateTime.getDayOfMonth());
    }

    @Override
    public void getMonitorDataByMonth() {
        //取前一月的时间
        LocalDateTime dateTime = LocalDateTime.now().plusMonths(-1);
        //保存日报表数据
        monitorDataMapper.batchInsertYearReport(dateTime.getYear(),dateTime.getMonthValue());
    }



}