package com.pqs9000.serviceimpl.responsibility;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.njcn.pojo.commons.AreaGeneralData;
import com.njcn.pojo.commons.RedisDB;
import com.njcn.utils.UserUtil;
import com.njcn.utils.redis.JedisManager;
import com.pqs9000.mapper.responsibility.AreaOverNormalMapper;
import com.pqs9000.mapper.responsibility.DataHarmonicDetailMapper;
import com.pqs9000.mapper.responsibility.OverLimitMonitorMapper;
import com.pqs9000.pojo.data.DataHarmonicDetail;
import com.pqs9000.pojo.responsibility.OverLimitMonitor;
import com.pqs9000.pojo.responsibility.TargetDetailDto;
import com.pqs9000.service.responsibility.OverLimitMonitorService;
import com.pqs9000.util.Kafka.JavaKafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author xuyang
 * @date 2020/11/2 9:04
 */
@Service
public class OverLimitMonitorServiceImpl implements OverLimitMonitorService {

    private static final Logger logger = LoggerFactory.getLogger(OverLimitMonitorServiceImpl.class);

    @Autowired
    private UserUtil userUtil;

    @Autowired
    private OverLimitMonitorMapper overLimitMonitorMapper;

    @Autowired
    private AreaOverNormalMapper areaOverNormalMapper;

    @Autowired
    private JedisManager jedisManager;

    @Autowired
    private DataHarmonicDetailMapper dataHarmonicDetailMapper;

    @Override
    public List<OverLimitMonitor> getOverLimitMonitorData(String startTime, String endTime, String tigName, String area, String vollevel,boolean statFlag) {
        List<OverLimitMonitor> allMonitorList;
        List<AreaGeneralData> ag;
        List<Integer> monitor = new ArrayList<>();
        //新增统计类型判断
        if(statFlag){
            ag = userUtil.getAreaDataByInfoRun(area);
        }else {
            //排除不需要计算的监测点
            ag =userUtil.getAreaDataByStatFlagAll(area);
        }
        //将区域参数传入sql
        if ("null".equals(vollevel)){
            vollevel = "";
        }
        //判断是不是国网类型监测点
        ag = judgeMonitor(tigName,ag);
        for (AreaGeneralData pojo:ag) {
            monitor.addAll(pojo.getLineIndexs());
        }
        allMonitorList = getData(monitor,startTime,endTime,vollevel);
        //将详细数据赋值给返回体
        if (CollUtil.isNotEmpty(allMonitorList)) {
            // 查询对应时间的稳态值表详情
            List<DataHarmonicDetail> maxList = dataHarmonicDetailMapper.selectMaxData(startTime, endTime, monitor);
            if (CollUtil.isNotEmpty(maxList)) {
                Map<Integer, List<DataHarmonicDetail>> map = maxList.stream().collect(Collectors.groupingBy(DataHarmonicDetail::getTargetType));
                map.forEach((key, value) -> updateAllMonitorList(allMonitorList, key, value));
            }
        }
        String json = JSON.toJSONString(allMonitorList);
        jedisManager.saveValueByKey(RedisDB.REPORTID,RedisDB.MONITORREPORTNAME,json,3600);
        return allMonitorList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void manualCalculation(String startTime, String endTime) throws Exception{
        //获取需要计算的监测点集合
        List<String> lineList = overLimitMonitorMapper.getLineList(startTime,endTime);
        if (CollUtil.isNotEmpty(lineList)){
            this.calculateAndAddDetailsDaily(startTime, endTime, lineList);
        }
    }

    private void calculateAndAddDetailsDaily(String startTime, String endTime, List<String> lineList) throws Exception{
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDate = LocalDate.parse(startTime, dateFormatter);
        LocalDate endDate = LocalDate.parse(endTime, dateFormatter);
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            String time1 = date.atStartOfDay().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
            String time2 = date.atTime(23, 59, 59).format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
            addHarmonicDetail(time1, time2, lineList);
        }

    }

    //获取监测点具体参数
    private List<OverLimitMonitor> getData(List<Integer> monitorList,String startTime, String endTime,String vollevel) {
        List<OverLimitMonitor> list = new ArrayList<>();
        if (!monitorList.isEmpty()){
            list = overLimitMonitorMapper.getOverLimitMonitorList(monitorList,startTime,endTime,vollevel);
        }
        return  list;
    }

    //判断是不是国网监测点
    public List<AreaGeneralData> judgeMonitor(String type,List<AreaGeneralData> ag) {
        if ("南网".equals(type) || "国网".equals(type) || "灿能".equals(type)){
            List<Integer> countryList = new ArrayList<>();
            for (AreaGeneralData typeDate:ag) {
                if (typeDate.getMonitors() !=0 ){
                    countryList = countryMonitor(typeDate.getLineIndexs());
                }
                if (countryList.isEmpty()){
                    typeDate.setMonitors(0);
                } else {
                    typeDate.setMonitors(countryList.size());
                }
                typeDate.setLineIndexs(countryList);
            }
        }
        return ag;
    }

    //获取国网监测点
    public List<Integer> countryMonitor(List<Integer> list){
        return areaOverNormalMapper.getCountryMonitor(list);
    }

    public void addHarmonicDetail(String startTime, String endTime, List<String> lineList) throws Exception {
        List<DataHarmonicDetail> result = new ArrayList<>();
        /**
         * 获取电压偏差的最大幅值绝对值、限值、差值
         */
        List<TargetDetailDto> list0 = overLimitMonitorMapper.getData0(startTime,endTime,lineList);
        /**
         * 获取电压偏差、电压总谐波畸变率、三相电压不平衡度、频率偏差 的 最大幅值、限值、差值
         */
        List<TargetDetailDto> list1 = overLimitMonitorMapper.getData1(startTime,endTime,lineList);
        /**
         * 负序电流 的 最大幅值、限值、差值
         */
        List<TargetDetailDto> list2 = overLimitMonitorMapper.getData2(startTime,endTime,lineList);
        /**
         * 长时闪变 的 最大幅值、限值、差值
         */
        List<TargetDetailDto> list3 = overLimitMonitorMapper.getData3(startTime,endTime,lineList);
        /**
         * 谐波电流各次幅值与限值的比值
         */
        List<TargetDetailDto> list4 = overLimitMonitorMapper.getData4(startTime,endTime,lineList);
        List<TargetDetailDto> list5 = new ArrayList<>();
        if (CollUtil.isNotEmpty(list4)){
            list4.forEach(item->{
                List<Double> l1 = Arrays.asList(item.getRatio1(),item.getRatio2(),item.getRatio3(),item.getRatio4(),item.getRatio5(),item.getRatio6(),item.getRatio7(),item.getRatio8(),item.getRatio9(),item.getRatio10()
                        ,item.getRatio11(),item.getRatio12(),item.getRatio13(),item.getRatio14(),item.getRatio15(),item.getRatio16(),item.getRatio17(),item.getRatio18(),item.getRatio19(),item.getRatio20(),item.getRatio21()
                        ,item.getRatio22(),item.getRatio23(),item.getRatio24());
                // 获取各次指标比值中的最大值
                Double max = l1.stream().mapToDouble(Double::doubleValue).max().orElse(Double.NaN);
                // 获取最大值的下标值
                int index = IntStream.range(0, l1.size())
                        .filter(i -> Objects.equals(max, l1.get(i)))
                        .findFirst()
                        .orElse(-1);
                //获取谐波电流是哪一次
                int time = this.getHarmonicTimes("harmonicI",index);
                list5.add(overLimitMonitorMapper.getHarmonicData1(startTime,endTime,item.getMonitorId(), time));
            });
        }
        /**
         * 谐波电压各次含有率、电压总谐波畸变率与限值的比值
         */
        List<TargetDetailDto> list6 = overLimitMonitorMapper.getData5(startTime,endTime,lineList);
        List<TargetDetailDto> list7 = new ArrayList<>();
        if (CollUtil.isNotEmpty(list6)){
            list6.forEach(item->{
                List<Double> l1 = Arrays.asList(item.getRatio1(),item.getRatio2(),item.getRatio3(),item.getRatio4(),item.getRatio5(),item.getRatio6(),item.getRatio7(),item.getRatio8(),item.getRatio9(),item.getRatio10()
                        ,item.getRatio11(),item.getRatio12(),item.getRatio13(),item.getRatio14(),item.getRatio15(),item.getRatio16(),item.getRatio17(),item.getRatio18(),item.getRatio19(),item.getRatio20(),item.getRatio21()
                        ,item.getRatio22(),item.getRatio23(),item.getRatio24(),item.getRatio25());
                // 获取各次指标比值中的最大值
                Double max = l1.stream().mapToDouble(Double::doubleValue).max().orElse(Double.NaN);
                // 获取最大值的下标值
                int index = IntStream.range(0, l1.size())
                        .filter(i -> Objects.equals(max, l1.get(i)))
                        .findFirst()
                        .orElse(-1);
                if (index == 0){
                    //电压总谐波畸变率
                    list7.add(overLimitMonitorMapper.getHarmonicData2(startTime,endTime,item.getMonitorId(), null));
                } else {
                    //获取谐波电压含有率是哪一次
                    int time = this.getHarmonicTimes("harmonicV",index);
                    list7.add(overLimitMonitorMapper.getHarmonicData3(startTime,endTime,item.getMonitorId(), time));
                }
            });
        }
        /**
         * 谐波电压各次含有率与限值的比值
         */
        List<TargetDetailDto> list8 = overLimitMonitorMapper.getData6(startTime,endTime,lineList);
        List<TargetDetailDto> list9 = new ArrayList<>();
        if (CollUtil.isNotEmpty(list8)){
            list8.forEach(item->{
                List<Double> l1 = Arrays.asList(item.getRatio2(),item.getRatio3(),item.getRatio4(),item.getRatio5(),item.getRatio6(),item.getRatio7(),item.getRatio8(),item.getRatio9(),item.getRatio10()
                        ,item.getRatio11(),item.getRatio12(),item.getRatio13(),item.getRatio14(),item.getRatio15(),item.getRatio16(),item.getRatio17(),item.getRatio18(),item.getRatio19(),item.getRatio20(),item.getRatio21()
                        ,item.getRatio22(),item.getRatio23(),item.getRatio24(),item.getRatio25());
                // 获取各次指标比值中的最大值
                Double max = l1.stream().mapToDouble(Double::doubleValue).max().orElse(Double.NaN);
                // 获取最大值的下标值
                int index = IntStream.range(0, l1.size())
                        .filter(i -> Objects.equals(max, l1.get(i)))
                        .findFirst()
                        .orElse(-1);
                //获取谐波电压含有率是哪一次
                int time = this.getHarmonicTimes("harmonicTimes",index);
                list9.add(overLimitMonitorMapper.getHarmonicData3(startTime,endTime,item.getMonitorId(), time));
            });
        }
        /**
         * 间谐波电压含有率与限值的比值
         */
        List<TargetDetailDto> list10 = overLimitMonitorMapper.getData7(startTime,endTime,lineList);
        List<TargetDetailDto> list11 = new ArrayList<>();
        if (CollUtil.isNotEmpty(list10)){
            list10.forEach(item->{
                List<Double> l1 = Arrays.asList(item.getRatio1(),item.getRatio2(),item.getRatio3(),item.getRatio4(),item.getRatio5(),item.getRatio6(),item.getRatio7(),item.getRatio8()
                        ,item.getRatio9(),item.getRatio10(),item.getRatio11(),item.getRatio12(),item.getRatio13(),item.getRatio14(),item.getRatio15(),item.getRatio16());
                // 获取各次指标比值中的最大值
                Double max = l1.stream().mapToDouble(Double::doubleValue).max().orElse(Double.NaN);
                // 获取最大值的下标值
                int index = IntStream.range(0, l1.size())
                        .filter(i -> Objects.equals(max, l1.get(i)))
                        .findFirst()
                        .orElse(-1);
                //获取间谐波电压含有率是哪一次
                int time = this.getHarmonicTimes("inuharmV",index);
                list11.add(overLimitMonitorMapper.getHarmonicData4(startTime,endTime,item.getMonitorId(), time));
            });
        }
        //设置日期
        SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.NORM_DATE_PATTERN);
        Date date = sdf.parse(startTime);
        //组装数据
        //type数据类型
        //0:电压偏差 1:谐波电流 2:谐波电压 3:电压总谐波畸变率 4:谐波电压含有率 5:频率偏差 6:间谐波电压含有率 7:三相电压不平衡度 8:负序电流 9:闪变
        if (CollUtil.isNotEmpty(list0)){
            list0.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setLineId(item.getMonitorId());
                pojo.setTargetType(0);
                if (Math.abs(item.getMaxVoltageDeviationData()) >= Math.abs(item.getMinVoltageDeviationData())) {
                    pojo.setMaxData(item.getMaxVoltageDeviationData());
                    pojo.setLimitData(item.getLimitUpVoltageDeviationData());
                    pojo.setDiffData(item.getMaxVoltageDeviationData()-item.getLimitUpVoltageDeviationData());
                } else {
                    pojo.setMaxData(item.getMinVoltageDeviationData());
                    pojo.setLimitData(item.getLimitLowVoltageDeviationData());
                    pojo.setDiffData(item.getMinVoltageDeviationData()-item.getLimitLowVoltageDeviationData());
                }
                result.add(pojo);
            });
        }
        if (CollUtil.isNotEmpty(list1)){
            list1.forEach(item->{
                DataHarmonicDetail pojo2 = new DataHarmonicDetail();
                pojo2.setTimeId(date);
                pojo2.setLineId(item.getMonitorId());
                pojo2.setTargetType(3);
                pojo2.setMaxData(item.getMaxVoltageDistortionData());
                pojo2.setLimitData(item.getLimitVoltageDistortionData());
                pojo2.setDiffData(item.getDiffVoltageDistortionData());
                result.add(pojo2);

                DataHarmonicDetail pojo3 = new DataHarmonicDetail();
                pojo3.setTimeId(date);
                pojo3.setLineId(item.getMonitorId());
                pojo3.setTargetType(5);
                pojo3.setMaxData(item.getMaxFrequencyDeviationData());
                pojo3.setLimitData(item.getLimitFrequencyDeviationData());
                pojo3.setDiffData(item.getDiffFrequencyDeviationData());
                result.add(pojo3);

                DataHarmonicDetail pojo4 = new DataHarmonicDetail();
                pojo4.setTimeId(date);
                pojo4.setLineId(item.getMonitorId());
                pojo4.setTargetType(7);
                pojo4.setMaxData(item.getMaxThreeVoltageUnbalanceData());
                pojo4.setLimitData(item.getLimitThreeVoltageUnbalanceData());
                pojo4.setDiffData(item.getDiffThreeVoltageUnbalanceData());
                result.add(pojo4);
            });
        }

        if (CollUtil.isNotEmpty(list2)){
            list2.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setTargetType(8);
                pojo.setLineId(item.getMonitorId());
                pojo.setMaxData(item.getMaxNegativeDay());
                pojo.setLimitData(item.getLimitNegativeData());
                pojo.setDiffData(item.getDiffNegativeData());
                result.add(pojo);
            });
        }

        if (CollUtil.isNotEmpty(list3)){
            list3.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setTargetType(9);
                pojo.setLineId(item.getMonitorId());
                pojo.setMaxData(item.getMaxFlickerData());
                pojo.setLimitData(item.getLimitFlickerData());
                pojo.setDiffData(item.getDiffFlickerData());
                result.add(pojo);
            });
        }

        if (CollUtil.isNotEmpty(list5)){
            list5.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setTargetType(1);
                pojo.setLineId(item.getMonitorId());
                pojo.setMaxData(item.getData2());
                pojo.setLimitData(item.getData1());
                pojo.setDiffData(item.getData2()-item.getData1());
                result.add(pojo);
            });
        }

        if (CollUtil.isNotEmpty(list7)){
            list7.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setTargetType(2);
                pojo.setLineId(item.getMonitorId());
                pojo.setMaxData(item.getData2());
                pojo.setLimitData(item.getData1());
                pojo.setDiffData(item.getData2()-item.getData1());
                result.add(pojo);
            });
        }

        if (CollUtil.isNotEmpty(list9)){
            list9.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setTargetType(4);
                pojo.setLineId(item.getMonitorId());
                pojo.setMaxData(item.getData2());
                pojo.setLimitData(item.getData1());
                pojo.setDiffData(item.getData2()-item.getData1());
                result.add(pojo);
            });
        }

        if (CollUtil.isNotEmpty(list11)){
            list9.forEach(item->{
                DataHarmonicDetail pojo = new DataHarmonicDetail();
                pojo.setTimeId(date);
                pojo.setTargetType(6);
                pojo.setLineId(item.getMonitorId());
                pojo.setMaxData(item.getData2());
                pojo.setLimitData(item.getData1());
                pojo.setDiffData(item.getData2()-item.getData1());
                result.add(pojo);
            });
        }
        if (CollUtil.isNotEmpty(result)){
            dataHarmonicDetailMapper.deleteData(startTime, endTime);
            dataHarmonicDetailMapper.insertData(result);
        }
    }

    //获取谐波次数
    public int getHarmonicTimes(String type, Integer index) {
        switch (type) {
            case "harmonicI":
            case "harmonicTimes":
                return index+2;
            case "inuharmV":
                return index+1;
            case "harmonicV":
                if (index != 0){
                    return index+1;
                }
            default:
                return 0;
        }
    }

    private void updateAllMonitorList(List<OverLimitMonitor> allMonitorList, Integer key, List<DataHarmonicDetail> value) {
        switch (key) {
            // 数据类型(0:电压偏差 1:谐波电流 2:谐波电压 3:电压总谐波畸变率 4:谐波电压含有率 5:频率偏差 6:间谐波电压含有率 7:三相电压不平衡度 8:负序电流 9:闪变)
            case 0:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverVoltageDeviationDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxVoltageDeviationData(p3.getMaxData());
                            p1.setLimitVoltageDeviationData(p3.getLimitData());
                            p1.setDiffVoltageDeviationData(p3.getDiffData());
                        }));
                break;
            case 1:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverHarmonicCurrentDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxHarmonicCurrentData(p3.getMaxData());
                            p1.setLimitHarmonicCurrentData(p3.getLimitData());
                            p1.setDiffHarmonicCurrentData(p3.getDiffData());
                        }));
                break;
            case 2:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverLimitHarmVDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxLimitHarmVData(p3.getMaxData());
                            p1.setLimitHarmVData(p3.getLimitData());
                            p1.setDiffHarmVData(p3.getDiffData());
                        }));
                break;
            case 3:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverVoltageDistortionDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxVoltageDistortionData(p3.getMaxData());
                            p1.setLimitVoltageDistortionData(p3.getLimitData());
                            p1.setDiffVoltageDistortionData(p3.getDiffData());
                        }));
                break;
            case 4:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverHarmonicVoltageDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxHarmonicVoltageData(p3.getMaxData());
                            p1.setLimitHarmonicVoltageData(p3.getLimitData());
                            p1.setDiffHarmonicVoltageData(p3.getDiffData());
                        }));
                break;
            case 5:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverFrequencyDeviationDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxFrequencyDeviationData(p3.getMaxData());
                            p1.setLimitFrequencyDeviationData(p3.getLimitData());
                            p1.setDiffFrequencyDeviationData(p3.getDiffData());
                        }));
                break;
            case 6:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverInterharmonicsDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxInterharmonicsData(p3.getMaxData());
                            p1.setLimitInterharmonicsData(p3.getLimitData());
                            p1.setDiffInterharmonicsData(p3.getDiffData());
                        }));
                break;
            case 7:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverThreeVoltageUnbalanceDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxThreeVoltageUnbalanceData(p3.getMaxData());
                            p1.setLimitThreeVoltageUnbalanceData(p3.getLimitData());
                            p1.setDiffThreeVoltageUnbalanceData(p3.getDiffData());
                        }));
                break;
            case 8:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverNegativeDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxNegativeDay(p3.getMaxData());
                            p1.setLimitNegativeData(p3.getLimitData());
                            p1.setDiffNegativeData(p3.getDiffData());
                        }));
                break;
            case 9:
                value.forEach(p3 -> allMonitorList.stream()
                        .filter(p1 -> Objects.equals(p1.getMonitorId(), p3.getLineId()) && p1.getOverFlickerDay() > 0)
                        .findFirst()
                        .ifPresent(p1 -> {
                            p1.setMaxFlickerData(p3.getMaxData());
                            p1.setLimitFlickerData(p3.getLimitData());
                            p1.setDiffFlickerData(p3.getDiffData());
                        }));
                break;
            default:
                break;
        }
    }


}
