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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.device.pms.api.DistributionMonitorClient;
import com.njcn.device.pms.api.MonitorClient;
import com.njcn.device.pms.pojo.po.DistributionMonitor;
import com.njcn.device.pms.pojo.po.Monitor;
import com.njcn.harmonic.pojo.po.RMpTargetWarnDPO;
import com.njcn.prepare.harmonic.mapper.mysql.area.RMpTargetWarnDMapper;
import com.njcn.prepare.harmonic.mapper.mysql.day.RStatDataVDMapper;
import com.njcn.prepare.harmonic.mapper.mysql.line.*;
import com.njcn.prepare.harmonic.pojo.dto.AlarmDetailDayDTO;
import com.njcn.prepare.harmonic.pojo.mysql.po.line.RMpTargetDiffDPO;
import com.njcn.prepare.harmonic.pojo.param.LineParam;
import com.njcn.prepare.harmonic.service.mysql.line.AlarmDetailService;
import com.njcn.prepare.harmonic.utils.PublicUtil;
import com.njcn.system.api.DicDataFeignClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 数据是否异常
 *
 * @author qijian
 * @version 1.0.0
 * @createTime 2022/11/29 - 10:09
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AlarmDetailServiceImpl extends MppServiceImpl<AlarmMapper, RMpTargetDiffDPO> implements AlarmDetailService {

    private final DistributionMonitorClient distributionMonitorClient;

    private final MonitorClient monitorClient;

    private final DicDataFeignClient dicDataFeignClient;

    private final RMpTargetWarnDMapper rMpTargetWarnDMapper;

    private final RMpMeasurePhaseReportDPOMapper rMpMeasurePhaseReportDPOMapper;

    private final RMpMeasureReportDPOMapper rMpMeasureReportDPOMapper;

    private final RMpHarmonicVRateReportDPOMapper rMpHarmonicVRateReportDPOMapper;

    private final RMpEventDetailDMapper rMpEventDetailDMapper;

    private final RMpPltReportDPOMapper rMpPltReportDPOMapper;

    private final RStatDataVDMapper rStatDataVDMapper;

    /**
     * 电压偏差告警日统计
     * @author qijian
     * @date 2022/12/28
     * @return
     */
    @Override
    @Async("asyncExecutor")
    public boolean alarmDetailAlarm(LineParam lineParam) {
        //初始化
        String date = lineParam.getDataDate();
        List<String> lineIds = lineParam.getLineIds();
        Integer type = lineParam.getType();

        //获取监测点数据，进行业务操作
        if (CollUtil.isEmpty(lineIds)){
            //先获取主网的监测点信息，再获取配网的监测点信息
            List<Monitor> monitorList = monitorClient.getMonitorList(lineIds).getData();
            for (Monitor monitor : monitorList) {
                processVoltageDeviationAlarm(date,type, monitor.getLineId());
                processFrequencyDeviationAlarm(date,type, monitor.getLineId());
                processUnbalance95Alarm(date,type, monitor.getLineId());
                processVoltageHarmonicThd95Alarm(date,type, monitor.getLineId());
                processFlashingAlarm(date,type, monitor.getLineId());
                processSagTimesAlarm(date,type, monitor.getLineId());
                processInterruptTimesAlarm(date,type, monitor.getLineId());
            }
            List<DistributionMonitor> distributionMonitorList = distributionMonitorClient.distributionMonitorList(lineIds).getData();
            for (DistributionMonitor distributionMonitor : distributionMonitorList) {
                processVoltageDeviationAlarm(date,type, distributionMonitor.getMonitorId());
                processFrequencyDeviationAlarm(date,type, distributionMonitor.getMonitorId());
                processUnbalance95Alarm(date,type, distributionMonitor.getMonitorId());
                processVoltageHarmonicThd95Alarm(date,type, distributionMonitor.getMonitorId());
                processFlashingAlarm(date,type, distributionMonitor.getMonitorId());
                processSagTimesAlarm(date,type, distributionMonitor.getMonitorId());
                processInterruptTimesAlarm(date,type, distributionMonitor.getMonitorId());
            }
        } else {
            //根据监测点类型取数据
            for (String lineId : lineIds) {
                processVoltageDeviationAlarm(date,type, lineId);
                processFrequencyDeviationAlarm(date,type, lineId);
                processUnbalance95Alarm(date,type, lineId);
                processVoltageHarmonicThd95Alarm(date,type, lineId);
                processFlashingAlarm(date,type, lineId);
                processSagTimesAlarm(date,type, lineId);
                processInterruptTimesAlarm(date,type, lineId);
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    @Async("asyncExecutor")
    public void targetDiff(LineParam lineParam) {
        String startTime,endTime;
        //月处理
        if (lineParam.getType() == 3){
            int year = Integer.parseInt(lineParam.getDataDate().split("-")[0]);
            int month = Integer.parseInt(lineParam.getDataDate().split("-")[1]);
            List<String> dayList = PublicUtil.getDayByMonth(year,month);
            for (String item : dayList) {
                log.info(item+"-->开始执行");
                startTime = item + " 00:00:00";
                endTime = PublicUtil.getYesterday(item) +  " 00:00:00";
                diffData(startTime,endTime,lineParam.getLineIds());
            }
        }
        //日处理
        else {
            startTime = lineParam.getDataDate() + " 00:00:00";
            endTime = PublicUtil.getYesterday(lineParam.getDataDate()) +  " 00:00:00";
            diffData(startTime,endTime,lineParam.getLineIds());
        }
    }

    @Override
    public List<AlarmDetailDayDTO> getAvgDiffData(String time,List<String> list) {
        String endTime = PublicUtil.getLastYearDay(time);
        //计算本年的rm值
        return this.baseMapper.getAvgDiffData(endTime,time,list);
    }

    /**
     * 生成指标差值日统计
     */
    public void diffData(String startTime, String endTime, List<String> list) {
        List<RMpTargetDiffDPO> localData = rStatDataVDMapper.getDayData(startTime,list);
        List<RMpTargetDiffDPO> yesterdayData = rStatDataVDMapper.getDayData(endTime,list);
        if (!CollectionUtils.isEmpty(localData) && !CollectionUtils.isEmpty(yesterdayData)){
            //取两个集合的交集,做算法处理取绝对值
            List<RMpTargetDiffDPO> intersectionList = localData.stream().map(map->yesterdayData.stream().filter(m->Objects.equals(m.getLineId(),map.getLineId())).findFirst().map(m->{
                map.setVlDev(Math.abs(map.getVlDev()-m.getVlDev()));
                map.setFreqDev(Math.abs(map.getFreqDev()-m.getFreqDev()));
                map.setVUnbalance(Math.abs(map.getVUnbalance()-m.getVUnbalance()));
                map.setVHarmonic(Math.abs(map.getVHarmonic()-m.getVHarmonic()));
                map.setPlt(Math.abs(map.getPlt()-m.getPlt()));
                map.setSagTimes(Math.abs(map.getSagTimes()-m.getSagTimes()));
                map.setInterruptTimes(Math.abs(map.getInterruptTimes()-m.getInterruptTimes()));
                return map;
            }).orElse(null)).filter(Objects::nonNull).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(intersectionList)){
                this.saveOrUpdateBatchByMultiId(intersectionList,50);
            }
        }
    }

    /**
     * 处理数据（电压偏差告警日统计）
     * @author qijian
     * @date 2022/12/28
     */
    private void processVoltageDeviationAlarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        double localMax = rMpMeasurePhaseReportDPOMapper.getMaxVDeUp(lineId, localDate);
        double yesterdayMax = rMpMeasurePhaseReportDPOMapper.getMaxVDeUp(lineId, yesterday);
        double beforeYesterdayMax = rMpMeasurePhaseReportDPOMapper.getMaxVDeUp(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsVDevWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsVDevWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 处理数据（频率偏差告警日统计）
     * @author qijian
     * @date 2022/12/29
     */
    private void processFrequencyDeviationAlarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        double localMax = rMpMeasureReportDPOMapper.getMaxFrequencyDeviation(lineId, localDate);
        double yesterdayMax = rMpMeasureReportDPOMapper.getMaxFrequencyDeviation(lineId, yesterday);
        double beforeYesterdayMax = rMpMeasureReportDPOMapper.getMaxFrequencyDeviation(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsFreqWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsFreqWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 处理数据（三相电压不平衡告警日统计）
     * @author qijian
     * @date 2022/12/29
     */
    private void processUnbalance95Alarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        double localMax = rMpMeasureReportDPOMapper.getMaxUnbalance95(lineId, localDate);
        double yesterdayMax = rMpMeasureReportDPOMapper.getMaxUnbalance95(lineId, yesterday);
        double beforeYesterdayMax = rMpMeasureReportDPOMapper.getMaxUnbalance95(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsUnbalanceWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsUnbalanceWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 处理数据（谐波电压告警日统计）
     * @author qijian
     * @date 2022/12/29
     */
    private void processVoltageHarmonicThd95Alarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        double localMax = rMpHarmonicVRateReportDPOMapper.getMaxVoltageHarmonicThd95(lineId, localDate);
        double yesterdayMax = rMpHarmonicVRateReportDPOMapper.getMaxVoltageHarmonicThd95(lineId, yesterday);
        double beforeYesterdayMax = rMpHarmonicVRateReportDPOMapper.getMaxVoltageHarmonicThd95(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsVWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsVWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 处理数据（长时电压闪变告警日统计）
     * @author qijian
     * @date 2022/12/30
     */
    private void processFlashingAlarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        double localMax = rMpPltReportDPOMapper.getMaxFlashing(lineId, localDate);
        double yesterdayMax = rMpPltReportDPOMapper.getMaxFlashing(lineId, yesterday);
        double beforeYesterdayMax = rMpPltReportDPOMapper.getMaxFlashing(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsFlickerWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsFlickerWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 处理数据（电压暂降告警日统计）
     * @author qijian
     * @date 2022/12/29
     */
    private void processSagTimesAlarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        int localMax = rMpEventDetailDMapper.getSagTimes(lineId, localDate);
        int yesterdayMax = rMpEventDetailDMapper.getSagTimes(lineId, yesterday);
        int beforeYesterdayMax = rMpEventDetailDMapper.getSagTimes(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsSagWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsSagWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 处理数据（电压短时中断告警日统计）
     * @author qijian
     * @date 2022/12/29
     */
    private void processInterruptTimesAlarm(String date, Integer type, String lineId) {
        //日期条件（取前天、昨天、今天）
        LocalDate localDate = LocalDate.parse(date);
        LocalDate yesterday = localDate.plusDays(-1);
        LocalDate beforeYesterday = yesterday.plusDays(-1);
        int localMax = rMpEventDetailDMapper.getInterruptTimes(lineId, localDate);
        int yesterdayMax = rMpEventDetailDMapper.getInterruptTimes(lineId, yesterday);
        int beforeYesterdayMax = rMpEventDetailDMapper.getInterruptTimes(lineId, beforeYesterday);

        //计算RM和CL值
        double rm = ((localMax - yesterdayMax) + (yesterdayMax - beforeYesterdayMax)) / 2;
        double cl = (localMax + yesterdayMax + beforeYesterdayMax) / 3;

        //计算RL和UCL值
        double rl = rm * 3.3;
        double ucl = cl + rm * 3;

        //如果本日最大值>UCL 且 本日最大值>昨日最大值，则告警
        if (localMax > ucl && localMax > yesterdayMax){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsInterruptWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }

        //如果本日>昨日>前日，且前日的值超过RL值，则告警
        if (localMax > yesterdayMax && yesterdayMax > beforeYesterdayMax && beforeYesterdayMax > rl){
            RMpTargetWarnDPO rMpTargetWarnD = new RMpTargetWarnDPO();
            rMpTargetWarnD.setMeasurementPointId(lineId);
            rMpTargetWarnD.setDataDate(DateUtil.parse(date));
            rMpTargetWarnD.setIsInterruptWarn(1);
            addAlarmData(rMpTargetWarnD);
            return;
        }
    }

    /**
     * 存入数据库
     * @author qijian
     * @date 2022/12/28
     */
    private void addAlarmData(RMpTargetWarnDPO rMpTargetWarnD) {
        LambdaQueryWrapper<RMpTargetWarnDPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(RMpTargetWarnDPO::getMeasurementPointId, rMpTargetWarnD.getMeasurementPointId()).eq(RMpTargetWarnDPO::getDataDate, rMpTargetWarnD.getDataDate());
        RMpTargetWarnDPO rMpTargetWarnDOne = rMpTargetWarnDMapper.selectOne(lambdaQueryWrapper);
        if (Objects.nonNull(rMpTargetWarnDOne)) {
            rMpTargetWarnDMapper.update(rMpTargetWarnD, lambdaQueryWrapper);
        } else {
            rMpTargetWarnDMapper.insert(rMpTargetWarnD);
        }
    }
}
