package com.njcn.prepare.harmonic.service.mysql.Impl.line;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.device.pq.pojo.po.RStatOnlinerateD;
import com.njcn.energy.pojo.constant.ModelState;
import com.njcn.influx.deprecated.InfluxDBPublicParam;
import com.njcn.influx.pojo.po.PqsCommunicate;
import com.njcn.influx.utils.InfluxDbUtils;
import com.njcn.prepare.harmonic.mapper.mysql.day.RStatOnlineRateDMapper;
import com.njcn.prepare.harmonic.pojo.bo.CalculatedParam;
import com.njcn.prepare.harmonic.pojo.dto.OnLineRateDTO;

import com.njcn.prepare.harmonic.service.mysql.line.OnlineRateService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.influxdb.dto.QueryResult;
import org.influxdb.impl.InfluxDBResultMapper;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;


/**
 * 生成在线率数据
 *
 * @author xiaoyao
 * @version 1.0.0
 * @createTime 2022/10/27 9:23
 */
@Slf4j
@Service
@AllArgsConstructor
public class OnlineRateServiceImpl extends MppServiceImpl<RStatOnlineRateDMapper, RStatOnlinerateD> implements OnlineRateService {

    private final InfluxDbUtils influxDbUtils;


    @Override
    public void deviceOnlineRate(CalculatedParam calculatedParam) {
        List<String> devList = calculatedParam.getIdList();
        String data = LocalDateTimeUtil.format(
                LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.parse(calculatedParam.getDataDate(), DatePattern.NORM_DATE_PATTERN)),
                DatePattern.NORM_DATETIME_PATTERN
        );
        LocalDate dateTime = LocalDate.parse(data,DatePattern.NORM_DATETIME_FORMATTER);
        List<PqsCommunicate> outCommunicateData = new ArrayList<>();
        for (String dev : devList){
            List<PqsCommunicate> communicateData = getCommunicateData(dev);
            outCommunicateData.addAll(communicateData);
        }
        List<RStatOnlinerateD> list = new ArrayList<>();
        Date dateOut = DateUtil.parse(calculatedParam.getDataDate());
        for (PqsCommunicate pqsCommunicate : outCommunicateData){
            RStatOnlinerateD onlineRateDpo = new RStatOnlinerateD();
            Date newDate = Date.from(pqsCommunicate.getTime());
            OnLineRateDTO onLineRate = onLineMinute(newDate,dateOut,pqsCommunicate.getType(),pqsCommunicate.getDevId(),calculatedParam.getDataDate());
            onlineRateDpo.setTimeId(dateTime);
            onlineRateDpo.setDevIndex(pqsCommunicate.getDevId());
            onlineRateDpo.setOnlineMin(onLineRate.getOnLineMinute());
            onlineRateDpo.setOfflineMin(onLineRate.getOffLineMinute());
            list.add(onlineRateDpo);
        }
        if (CollectionUtil.isNotEmpty(list)){
            this.saveOrUpdateBatchByMultiId(list,50);
        }
    }

    /**
     * 获取pqs_communicate数据
     */
    private List<PqsCommunicate> getCommunicateData(String lineId){
        QueryResult sqlResult = influxDbUtils.query("SELECT * FROM pqs_communicate where dev_id = '" + lineId +"' order by time desc limit 1 tz('Asia/Shanghai')");
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        return resultMapper.toPOJO(sqlResult, PqsCommunicate.class);
    }

    /**
     * 获取范围时间内的pqs_communicate数据
     */
    private List<PqsCommunicate> getCommunicateData(String lineId, String date){
        QueryResult sqlResult = influxDbUtils.query("SELECT * FROM pqs_communicate where time >= '" + date + " 00:00:00' and time <= '" + date + " 23:59:59' and dev_id = '" + lineId +"' order by time asc tz('Asia/Shanghai')");
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        return resultMapper.toPOJO(sqlResult, PqsCommunicate.class);
    }

    private List<PqsCommunicate> getCommunicateDataOld(String lineId, String date){
        QueryResult sqlResult = influxDbUtils.query("SELECT * FROM pqs_communicate where time <= '" + date + " 23:59:59' and dev_id = '" + lineId +"' order by time desc limit 1 tz('Asia/Shanghai')");
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        return resultMapper.toPOJO(sqlResult, PqsCommunicate.class);
    }

    /**
     * new的时间和当前统计时间 不是/是 同一天
     */
    private OnLineRateDTO onLineMinute(Date newDate, Date date, Integer type,String lineId,String dateStr){
        OnLineRateDTO onLineRate = new OnLineRateDTO();
        Integer minute = 0;
        /*new的时间和当前统计时间是同一天*/
        if (DateUtil.isSameDay(newDate,date)){
            minute = processData(newDate, date, type, lineId, dateStr);
        }else {
            /*new的时间和当前统计时间不是同一天*/
            Date nowDate = new Date();
            /*数据补招的情况下*/
            if (DateUtil.between(date,nowDate,DateUnit.DAY) > DateUtil.between(newDate,nowDate,DateUnit.DAY)){
                minute = processData(newDate, date, null, lineId, dateStr);
            }else {
                if (ModelState.online.equals(type)){
                    minute = InfluxDBPublicParam.DAY_MINUTE;
                }
            }
        }
        onLineRate.setOnLineMinute(minute);
        onLineRate.setOffLineMinute(InfluxDBPublicParam.DAY_MINUTE - minute);
        BigDecimal onLine = BigDecimal.valueOf(onLineRate.getOnLineMinute());
        BigDecimal offLine = BigDecimal.valueOf(onLineRate.getOffLineMinute());
        double rate = onLine.divide(onLine.add(offLine),4, RoundingMode.HALF_UP).doubleValue();
        onLineRate.setRate(rate*100);
        return onLineRate;
    }

    private Integer processData(Date newDate, Date date, Integer type,String lineId,String dateStr){
        int minute = 0;
        List<PqsCommunicate> communicateData = getCommunicateData(lineId,dateStr);
        /*当前统计时间内存在多条数据*/
        if (communicateData.size() > 1){
            Date lastTime = null;
            long onlineTime = 0;
            long offlineTime = 0;
            for (int i=0; i<communicateData.size(); i++){
                long differ;
                if (i==0){
                    /*首次比较取统计时间*/
                    differ = DateUtil.between(date,Date.from(communicateData.get(i).getTime()),DateUnit.MINUTE);
                }else {
                    /*后续取上一次数据时间*/
                    differ = DateUtil.between(lastTime,Date.from(communicateData.get(i).getTime()),DateUnit.MINUTE);
                }
                if (ModelState.online.equals(communicateData.get(i).getType())){
                    offlineTime = offlineTime + differ;
                }else {
                    onlineTime = onlineTime + differ;
                }
                lastTime = Date.from(communicateData.get(i).getTime());
            }
            if (ModelState.online.equals(communicateData.get(communicateData.size()-1).getType())){
                minute = InfluxDBPublicParam.DAY_MINUTE - (int)offlineTime;
            }else {
                minute = (int)onlineTime;
            }
        }else {
            if(type != null){
                /*当前统计时间内仅有一条数据*/
                long differ = DateUtil.between(date,newDate,DateUnit.MINUTE);
                if (ModelState.online.equals(type)){
                    minute = InfluxDBPublicParam.DAY_MINUTE - (int)differ;
                }
            }else {
                List<PqsCommunicate> communicateDataOld = getCommunicateDataOld(lineId,dateStr);
                if (communicateDataOld.size() > 0){
                    if (ModelState.online.equals(communicateDataOld.get(0).getType())){
                        minute = InfluxDBPublicParam.DAY_MINUTE;
                    }
                }
            }
        }
        return minute;
    }
}
