package com.njcn.prepare.harmonic.service.mysql.dim.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.device.biz.pojo.dto.DeptGetChildrenDTO;
import com.njcn.device.pms.pojo.po.Monitor;
import com.njcn.event.pojo.po.RMpEventDetailM;
import com.njcn.prepare.harmonic.mapper.mysql.area.PmsMonitorPOMapper;
import com.njcn.prepare.harmonic.mapper.mysql.dim.RDimObjEventMMapper;
import com.njcn.prepare.harmonic.mapper.mysql.line.RMpEventDetailMMapper;
import com.njcn.prepare.harmonic.mapper.mysql.line.ROperatingMonitorMMapper;
import com.njcn.prepare.harmonic.pojo.bo.CalculatedParam;
import com.njcn.prepare.harmonic.pojo.mysql.ROperatingMonitorMPO;
import com.njcn.prepare.harmonic.pojo.param.EventParam;
import com.njcn.harmonic.pojo.po.dim.RDimObjEventM;
import com.njcn.prepare.harmonic.service.mysql.dim.IRDimObjEventMService;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 监测到暂态指标的用户-月表 服务实现类
 * </p>
 *
 * @author xuyang
 * @since 2023-11-23
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RDimObjEventMServiceImpl extends MppServiceImpl<RDimObjEventMMapper, RDimObjEventM> implements IRDimObjEventMService {

    private final DicDataFeignClient dicDataFeignClient;
    private final RMpEventDetailMMapper rMpEventDetailMMapper;
    private final PmsMonitorPOMapper pmsMonitorPOMapper;
    private final ROperatingMonitorMMapper rOperatingMonitorMMapper;

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void eventUserRatioM(CalculatedParam<DeptGetChildrenDTO> calculatedParam) {
        log.info(LocalDateTime.now()+"===>监测点指标数据质量月表开始");
        List<RDimObjEventM> result = new ArrayList<>();
        List<DeptGetChildrenDTO> deptList = calculatedParam.getIdList();
        String beginMonth = DateUtil.format(DateUtil.beginOfMonth(DateUtil.parse(calculatedParam.getDataDate(), DatePattern.NORM_DATE_PATTERN)), DatePattern.NORM_DATE_PATTERN);
        //获取敏感用户、重要用户字典id
        String sensitiveUserId = dicDataFeignClient.getDicDataByCode(DicDataEnum.SENSITIVE_USERS.getCode()).getData().getId();
        String importantUserId = dicDataFeignClient.getDicDataByCode(DicDataEnum.IMPORTANT_USERS.getCode()).getData().getId();
        deptList.forEach(item->{
            RDimObjEventM rDimObjEventM = new RDimObjEventM();
            rDimObjEventM.setOrgId(item.getDeptId());
            rDimObjEventM.setStatisDate(LocalDate.parse(beginMonth, DatePattern.NORM_DATE_FORMATTER));
            rDimObjEventM.setMonitorRate(3.1415926f);
            rDimObjEventM.setLimitFreqRate(3.1415926f);
            List<String> lineList = item.getLineIds();
            if (CollectionUtil.isNotEmpty(lineList)){
                //获取当前单位下的重要用户、敏感用户监测点信息
                List<Monitor> monitorList = getUser(lineList, Arrays.asList(sensitiveUserId,importantUserId));
                if(CollectionUtil.isNotEmpty(monitorList)){
                    List<String> userList = monitorList.stream().map(Monitor::getId).collect(Collectors.toList());
                    //获取当前单位下的有效接入重要、敏感用户监测点信息
                    List<ROperatingMonitorMPO> effectiveList = getEffective(userList,beginMonth);
                    if (CollectionUtil.isNotEmpty(effectiveList)){
                        EventParam param = getEventTimes(userList,beginMonth);
                        //获取发生暂态的监测点数
                        rDimObjEventM.setMonitorRate((float)param.getEventLineCount()/effectiveList.size()*100);
                        //获取重要用户、敏感用户监测点发生的暂态次数之和
                        if (!Objects.equals(3.1415926f,param.getEventCount())){
                            rDimObjEventM.setLimitFreqRate(param.getEventCount()/effectiveList.size());
                        }
                    } else {
                        rDimObjEventM.setMonitorRate(-1.0f);
                        rDimObjEventM.setLimitFreqRate(-1.0f);
                    }
                }
            }
            result.add(rDimObjEventM);
        });
        if (CollectionUtil.isNotEmpty(result)){
            this.saveOrUpdateBatchByMultiId(result,100);
        }
    }

    public List<Monitor> getUser(List<String> lineList, List<String> monitorTag) {
        LambdaQueryWrapper<Monitor> monitorLambdaQueryWrapper = new LambdaQueryWrapper<>();
        monitorLambdaQueryWrapper.select(Monitor::getId, Monitor::getMonitorTag)
                .in(Monitor::getId, lineList)
                .in(Monitor::getMonitorTag, monitorTag)
                .eq(Monitor::getStatus, DataStateEnum.ENABLE.getCode());
        return pmsMonitorPOMapper.selectList(monitorLambdaQueryWrapper);
    }

    public List<ROperatingMonitorMPO> getEffective(List<String> lineList, String time) {
        LambdaQueryWrapper<ROperatingMonitorMPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(ROperatingMonitorMPO::getMeasurementPointId)
                .in(ROperatingMonitorMPO::getMeasurementPointId,lineList)
                .eq(ROperatingMonitorMPO::getDataDate,time)
                .ge(ROperatingMonitorMPO::getDataIntegrityRate,0.95)
                .eq(ROperatingMonitorMPO::getIsUnusual,DataStateEnum.ENABLE.getCode());
        return rOperatingMonitorMMapper.selectList(lambdaQueryWrapper);
    }

    public EventParam getEventTimes(List<String> lineList, String time) {
        EventParam eventParam = new EventParam();
        float result = 3.1415926f;
        int data = 0;
        int count = 0;
        LambdaQueryWrapper<RMpEventDetailM> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(RMpEventDetailM::getSwellTimes, RMpEventDetailM::getSagTimes, RMpEventDetailM::getInterruptTimes)
                .in(RMpEventDetailM::getMeasurementPointId,lineList)
                .eq(RMpEventDetailM::getDataDate,time);
        List<RMpEventDetailM> eventDay = rMpEventDetailMMapper.selectList(lambdaQueryWrapper);
        if (CollectionUtil.isNotEmpty(eventDay)){
            for (RMpEventDetailM item : eventDay) {
                int times = item.getSwellTimes() + item.getSagTimes() + item.getInterruptTimes();
                if (times == 0){
                    count++;
                }
                data = data + times;
            }
            result = (float) data;
        }
        eventParam.setEventLineCount(count);
        eventParam.setEventCount(result);
        return eventParam;
    }

}
