package com.njcn.device.pms.service.majornetwork.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Month;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.device.pms.mapper.majornetwork.RStatZwAlarmCountWMapper;
import com.njcn.device.pms.pojo.param.RStatZwAlarmCountWParam;
import com.njcn.device.pms.pojo.po.Monitor;
import com.njcn.device.pms.pojo.po.RMpTargetWarnD;
import com.njcn.device.pms.pojo.po.RStatZwAlarmCountW;
import com.njcn.device.pms.pojo.po.StatationStat;
import com.njcn.device.pms.pojo.vo.ProblemMonitorDetailVO;
import com.njcn.device.pms.pojo.vo.RStatZwAlarmCountWVO;
import com.njcn.device.pms.service.distribution.RMpPwAlarmDetailDService;
import com.njcn.device.pms.service.majornetwork.IMonitorService;
import com.njcn.device.pms.service.majornetwork.IStatationStatService;
import com.njcn.device.pms.service.majornetwork.RMpTargetWarnDService;
import com.njcn.device.pms.service.majornetwork.RStatZwAlarmCountWService;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.dto.DeptDTO;
import com.njcn.web.utils.WebUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author jianghf
* @description 针对表【r_stat_zw_alarm_count_w】的数据库操作Service实现
* @createDate 2022-10-08 16:35:44
*/
@Service
@RequiredArgsConstructor
public class RStatZwAlarmCountWServiceImpl extends ServiceImpl<RStatZwAlarmCountWMapper, RStatZwAlarmCountW>
implements RStatZwAlarmCountWService {

    private final DeptFeignClient deptFeignClient;

    private final RMpPwAlarmDetailDService rMpPwAlarmDetailDService; //【告警明细-日表】服务类

    private final RMpTargetWarnDService rMpTargetWarnDService; // 【监测点指标告警明细日表】服务类

    private final IMonitorService iMonitorService; //【监测点】服务类

    private final IStatationStatService iStatationStatService; //【变电站】服务类

    private final DicDataFeignClient dicDataFeignClient; //字典
    /***
     * 查询所有告警统计(周)
     * @author jianghaifei
     * @date 2022-10-09 10:22
     * @param
     * @return java.util.List<com.njcn.device.pms.pojo.po.RStatZwAlarmCountW>
     */
    @Override
    public List<RStatZwAlarmCountWVO> getAllRStatZwAlarmCountWList(RStatZwAlarmCountWParam rStatZwAlarmCountWParam) {
        //获取查询条件
        String id = rStatZwAlarmCountWParam.getId(); //单位id
        if (StringUtils.isBlank(id)) {
            throw new BusinessException(CommonResponseEnum.NO_DATA, "单位id不可为空");
        }
        String startTime = rStatZwAlarmCountWParam.getStartTime(); //开始时间 yyyy-MM-dd
        String endTime = rStatZwAlarmCountWParam.getEndTime(); //截止时间 yyyy-MM-dd
        //获取所有子部门信息
//        List<DeptDTO> deptDTOList = deptFeignClient.getDeptDescendantIndexes(id, WebUtil.filterDeptType()).getData();
        /*获取下级子部门信息*/
        List<DeptDTO> deptDTOList = deptFeignClient.getDepSonDetailByDeptId (id).getData ( );

        if (CollUtil.isEmpty(deptDTOList)) {
            throw new BusinessException(CommonResponseEnum.NO_DATA, "部门不存在");
        }
        //单位id集合
        List<String> orgCodeList = deptDTOList.stream().map(DeptDTO::getCode).collect(Collectors.toList());
        //将单位信息转为map集合 key: 单位id  value: 单位实体
        Map<String, DeptDTO> deptDTOMap = deptDTOList.stream().collect(Collectors.toMap(DeptDTO::getCode, deptDTO -> deptDTO));

        LambdaQueryWrapper<RStatZwAlarmCountW> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //条件组装: where org_no in (orgNoList) and data_date >= startTime and data_date <= endTime
        lambdaQueryWrapper.in(CollUtil.isNotEmpty(orgCodeList), RStatZwAlarmCountW::getOrgNo, orgCodeList)
                .ge(StringUtils.isNotBlank(startTime), RStatZwAlarmCountW::getDataDate, startTime)
                .le(StringUtils.isNotBlank(endTime), RStatZwAlarmCountW::getDataDate, endTime);
        //查询告警统计(周)集合
        List<RStatZwAlarmCountW> records = this.list(lambdaQueryWrapper);
        List<RStatZwAlarmCountWVO> resultList;
        if (CollUtil.isNotEmpty(records)) {
            resultList = records.stream().map(item -> {
                RStatZwAlarmCountWVO rStatZwAlarmCountWVO = new RStatZwAlarmCountWVO();
                BeanUtils.copyProperties(item, rStatZwAlarmCountWVO);
                //单位名称
                rStatZwAlarmCountWVO.setOrgName(deptDTOMap.get(rStatZwAlarmCountWVO.getOrgNo()).getName());
//                DecimalFormat df = new DecimalFormat("###.00");
                //获取有效监测点数量
                Integer monitorEffectiveCount = item.getMonitorEffectiveCount();
                //todo 有效监测点数量在实际环境中是可能为0的,不需要做异常处理
//                if (monitorEffectiveCount == null || monitorEffectiveCount <= 0) {
//                    throw new BusinessException(CommonResponseEnum.NO_DATA, "有效监测点数量异常");
//                }
                //计算告警四次及以上监测点占比（ * 100 是直接取到百分比）
//                Double warnMonitorRate = Double.parseDouble(df.format(item.getWarnMonitorCount() / (monitorEffectiveCount * 1.0) * 100));
                Double warnMonitorRate = monitorEffectiveCount<=0 ? 0.0 : Double.parseDouble(String.format("%.2f",item.getWarnMonitorCount() / (monitorEffectiveCount * 1.0) * 100));
                rStatZwAlarmCountWVO.setWarnMonitorRate(warnMonitorRate);
                //级别'较差'监测点占比（ * 100 是直接取到百分比）
//                Double monitorGradeRate = Double.parseDouble(df.format(item.getMonitorGradeCount() / (monitorEffectiveCount * 1.0) * 100));
                Double monitorGradeRate = monitorEffectiveCount<=0 ? 0.0 : Double.parseDouble(String.format("%.2f",item.getMonitorGradeCount() / (monitorEffectiveCount * 1.0) * 100));
                rStatZwAlarmCountWVO.setMonitorGradeRate(monitorGradeRate);

                return rStatZwAlarmCountWVO;
            }).collect(Collectors.toList());
        } else {
            resultList = new ArrayList<>();
        }

        return resultList;
    }


    /***
     * 查询问题严重的监测点信息
     * @author jianghaifei
     * @date 2022-10-13 19:38
     * @param rStatZwAlarmCountWParam
     * @return java.util.List<com.njcn.device.pms.pojo.vo.ProblemMonitorDetailVO>
     */
    @Override
    public List<ProblemMonitorDetailVO> getProblemMonitorDetailList(RStatZwAlarmCountWParam rStatZwAlarmCountWParam) {
        //提取参数
        String id = rStatZwAlarmCountWParam.getId(); //单位id
        String startTime = rStatZwAlarmCountWParam.getStartTime();
        String endTime = rStatZwAlarmCountWParam.getEndTime();

        //获取电压等级的字典
        List<DictData> voltageLevelList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_VOLTAGE.getCode()).getData();
        //将电压信息转成map，key：id  value：name
        Map<String, String> voltageLevelMap = voltageLevelList.stream().collect(Collectors.toMap(DictData::getId, DictData::getName));
        //查询当前单位下监测点idList
        LambdaQueryWrapper<Monitor> monitorLambdaQueryWrapper = new LambdaQueryWrapper<>();
        monitorLambdaQueryWrapper.eq(Monitor::getOrgId, id);
        List<String> orgMeasurementPointIdList = iMonitorService.list(monitorLambdaQueryWrapper).stream().map(Monitor::getId).collect(Collectors.toList());
        //如果单位下没有监测点，直接返回空集合
        if (CollUtil.isEmpty(orgMeasurementPointIdList)) {
            return new ArrayList<>();
        }
        //以周为时间段，查询告警超过四次的监测点信息
        LambdaQueryWrapper<RMpTargetWarnD> targetWarnWrapper = new LambdaQueryWrapper<>();
        targetWarnWrapper.select(RMpTargetWarnD::getMeasurementPointId)
                .in(RMpTargetWarnD::getMeasurementPointId, orgMeasurementPointIdList)
                .ge(StringUtils.isNotBlank(startTime), RMpTargetWarnD::getDataDate, startTime)
                .le(StringUtils.isNotBlank(endTime), RMpTargetWarnD::getDataDate, endTime)
                .groupBy(RMpTargetWarnD::getMeasurementPointId)
                //拼接条件
                .and(qw ->
                qw.eq(RMpTargetWarnD::getIsEffective, 0)//是否是有效接入监测点(0:否 1:是)
                .or() //开始拼接or条件
                .eq(RMpTargetWarnD::getIsHarmonic, 1)//是否是稳态超标监测点(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsEvent, 1) //是否是发生暂态的监测点(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsWarn, 1) //是否是告警监测点数(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsVDevWarn, 1) //电压偏差是否告警(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsFreqWarn, 1) //频率偏差是否告警(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsUnbalanceWarn, 1) //三相电压不平衡度是否告警(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsVWarn, 1) //谐波电压是否告警(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsFlickerWarn, 1) //闪变是否告警(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsSagWarn, 1) //电压暂降是否告警(0:否 1:是)
                .or()
                .eq(RMpTargetWarnD::getIsInterruptWarn, 1) //短时中断是否告警(0:否 1:是)
                )
                .having("count(measurement_point_id) >= {0}", 4);

//        LambdaQueryWrapper<RMpPwAlarmDetailD> alarmDetailWrapper = new LambdaQueryWrapper<>();
        /*
        组装查询条件：select count(1) from r_mp_pw_alarm_detail_d where data_date <= '2022-10-23'
             and data_date >= '2022-10-17' and measurement_point_id in (orgMeasurementPointIdList)
             group by measurement_point_id having count(measurement_point_id) >= 4
         */
//        alarmDetailWrapper.select(RMpPwAlarmDetailD::getMeasurementPointId)
//                .in(RMpPwAlarmDetailD::getMeasurementPointId, orgMeasurementPointIdList)
//                .ge(StringUtils.isNotBlank(startTime), RMpPwAlarmDetailD::getDataDate, startTime)
//                .le(StringUtils.isNotBlank(endTime), RMpPwAlarmDetailD::getDataDate, endTime)
//                .groupBy(RMpPwAlarmDetailD::getMeasurementPointId)
//                .having("count(measurement_point_id) >= {0}", 4);
        //告警超过四次的监测点idList
        List<String> measurementPointIdList = rMpTargetWarnDService.listObjs(targetWarnWrapper, Object::toString);

        // 计算问题严重的监测点
        //  获取查询条件：月份开始时间、结束时间
        Date date = DateUtil.parse(startTime);
        String startTimeOfMonth = DateUtil.format(DateUtil.beginOfMonth(date), "yyyy-MM-dd");
        String endTimeOfMonth = DateUtil.format(DateUtil.endOfMonth(date), "yyyy-MM-dd");
        //获取查询月份的自然月天数
        int monthDay = Month.of(DateUtil.month(date)).getLastDay(DateUtil.isLeapYear(DateUtil.year(date)));

        //根据单位下监测点idList、月份条件查询监测点告警信息
        List<RMpTargetWarnD> targetWarnDList;

        targetWarnWrapper.clear();
        //组装查询条件：
        targetWarnWrapper.in(RMpTargetWarnD::getMeasurementPointId, orgMeasurementPointIdList)
                .ge(StringUtils.isNotBlank(startTime), RMpTargetWarnD::getDataDate, startTimeOfMonth)
                .le(StringUtils.isNotBlank(endTime), RMpTargetWarnD::getDataDate, endTimeOfMonth);
        targetWarnDList = rMpTargetWarnDService.list(targetWarnWrapper);

        //使用stream的分组方法（Collectors.partitioningBy()）对告警记录和没有告警的记录进行分组 true：有告警的记录 false：没有告警的记录
//        Map<Boolean, List<RMpTargetWarnD>> booleanListMap = targetWarnDList.stream().collect(Collectors.groupingBy(
//                item -> item.getIsEffective() == 1 || item.getIsHarmonic() == 1 || item.getIsEvent() == 1 || item.getIsWarn() == 1
//                || item.getIsVDevWarn() == 1 || item.getIsFreqWarn() == 1 || item.getIsUnbalanceWarn() == 1 || item.getIsVWarn() == 1
//                || item.getIsFlickerWarn() == 1 || item.getIsSagWarn() == 1 || item.getIsInterruptWarn() == 1));
        //提取有告警情况的记录
//        List<RMpTargetWarnD> rMpTargetWarnDS4Warn = booleanListMap.get(true);
        //提取没有告警情况的记录
//        List<RMpTargetWarnD> rMpTargetWarnDS4Normal = booleanListMap.get(true);
        //过滤出有告警信息的记录
        List<RMpTargetWarnD> rMpTargetWarnDS4Warn = targetWarnDList.stream().filter(
                item -> item.getIsEffective() == 1 || item.getIsHarmonic() == 1 || item.getIsEvent() == 1 || item.getIsWarn() == 1
                        || item.getIsVDevWarn() == 1 || item.getIsFreqWarn() == 1 || item.getIsUnbalanceWarn() == 1 || item.getIsVWarn() == 1
                        || item.getIsFlickerWarn() == 1 || item.getIsSagWarn() == 1 || item.getIsInterruptWarn() == 1).collect(Collectors.toList());
        //创建map集合，用于统计某个监测点的记录条数
        HashMap<String, Integer> monitorCountMap = new HashMap<>();
        for (RMpTargetWarnD item : rMpTargetWarnDS4Warn) {
            if (monitorCountMap.containsKey(item.getMeasurementPointId())) {
                monitorCountMap.put(item.getMeasurementPointId(), monitorCountMap.get(item.getMeasurementPointId()) + 1);
            } else {
                monitorCountMap.put(item.getMeasurementPointId(), 1);
            }
        }
        //创建map集合，key：监测点id  value：严重程度
        HashMap<String, Double> severityMap = new HashMap<>();
        for (String measurementPointId : monitorCountMap.keySet()) {
            Integer integer = monitorCountMap.get(measurementPointId); //当前遍历的监测点告警天数
            double severity = integer / (monthDay * 1.0); //严重程度
            severityMap.put(measurementPointId, severity);
        }
        //给严重程度从大到小排序，并将严重程度前【30%】的监测点id放到List集合中
//        List<String> severity = new ArrayList<>();
//        severityMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList())
//                .subList(0, (int)(severityMap.size() * 0.3)).forEach(item -> severity.add(item.getKey()));
        List<String> severity = severityMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .limit((int)Math.ceil(severityMap.size() * 0.3)).map(Map.Entry::getKey).collect(Collectors.toList());
        //合并告警超过四次的监测点ids和严重程度前30%监测点dis
        measurementPointIdList.addAll(severity);
        //如果问题严重监测点id集合是空的，那直接返回空集合
        if (CollUtil.isEmpty(measurementPointIdList)) {
            return new ArrayList<>();
        }
        //去除集合中重复的监测点id，得到最终的有严重问题的监测点id集合
        List<String> lastMeasurementPointList = measurementPointIdList.stream().distinct().collect(Collectors.toList());
        //根据监测点ids查询监测点信息
        monitorLambdaQueryWrapper.clear();
        monitorLambdaQueryWrapper.in(Monitor::getId, lastMeasurementPointList);
        List<Monitor> monitorList = iMonitorService.list(monitorLambdaQueryWrapper);
        //提取出监测点相关的变电站id，获取变电站电压等级map（key: 变电站id  value: 电压等级）
        List<String> powerIdList = monitorList.stream().map(Monitor::getPowerrId).collect(Collectors.toList());
        LambdaQueryWrapper<StatationStat> stationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        stationLambdaQueryWrapper.in(StatationStat::getPowerId, powerIdList);
        Map<String, String> stationVoltageLevelMap = iStatationStatService.list(stationLambdaQueryWrapper).stream()
                .collect(Collectors.toMap(StatationStat::getPowerId, StatationStat::getVoltageLevel));
        //封装返回数据
        List<ProblemMonitorDetailVO> resultList = monitorList.stream().map(item -> {
            ProblemMonitorDetailVO problemMonitorDetailVO = new ProblemMonitorDetailVO();
            problemMonitorDetailVO.setOrgNo(item.getOrgId()); //单位id
            problemMonitorDetailVO.setOrgName(item.getOrgName()); //单位名称
            problemMonitorDetailVO.setMonitorId(item.getId()); //监测点id
            problemMonitorDetailVO.setMonitorName(item.getName()); //监测点名称
            problemMonitorDetailVO.setPowerName(item.getPowerrName()); //变电站名称
            problemMonitorDetailVO.setVoltageLevel(stationVoltageLevelMap.get(item.getPowerrId())); //变电站电压等级id
            problemMonitorDetailVO.setVoltageLevelName(voltageLevelMap.get(stationVoltageLevelMap.get(item.getPowerrId()))); //变电站电压等级

            return problemMonitorDetailVO;
        }).collect(Collectors.toList());
        return resultList;
    }
}
