package com.njcn.energy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.energy.mapper.EleIntegrityMapper;
import com.njcn.energy.pojo.constant.ModelState;
import com.njcn.energy.pojo.dto.ElePublicDTO;
import com.njcn.energy.pojo.po.*;
import com.njcn.energy.pojo.vo.EleIntegrityVO;
import com.njcn.energy.service.*;
import com.njcn.influx.utils.InfluxDbUtils;
import lombok.AllArgsConstructor;
import org.influxdb.dto.QueryResult;
import org.influxdb.impl.InfluxDBResultMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 类的介绍：
 *
 * @author xuyang
 * @version 1.0.0
 * @createTime 2022/3/31 19:40
 */
@AllArgsConstructor
@Service
public class EleIntegrityServiceImpl extends ServiceImpl<EleIntegrityMapper, EleIntegrity> implements IEleIntegrityService {

    private final INetDevService netDevService;

    private final ILogicDeviceLineService logicDeviceLineService;

    private final IEleLineService eleLineService;

    private final ILogicAccessService logicAccessService;

    private final InfluxDbUtils influxDbUtils;

    @Override
    public List<EleIntegrityVO> getIntegrityTree(String startTime, String endTime) {
        List<EleIntegrityVO> netDevIntegrity = new ArrayList<>(),logicDevIntegrity = new ArrayList<>(),lineIntegrity = new ArrayList<>();
        //获取所有网关
        List<NetDev> netDevList = netDevService.getAllNetDev();
        List<String> netDevId = netDevList.stream().map(NetDev::getId).collect(Collectors.toList());
        //获取网关下所有的逻辑设备
        List<LogicDev> logicDevList = logicDeviceLineService.getLogicDevByList(netDevId);
        //获取逻辑设备绑定的监测点
        List<EleLine> eleLineList = eleLineService.getAllLines(logicDevList.stream().map(LogicDev::getId).collect(Collectors.toList()));
        //获取装置通讯状态
        List<LogicAccess> logicAccessList = logicAccessService.getLogicDevByList(netDevId);
        netDevList.forEach(item->{
            EleIntegrityVO eleIntegrityVO = new EleIntegrityVO();
            BeanUtil.copyProperties(item,eleIntegrityVO);
            eleIntegrityVO.setComFlag(item.getComFlag());
            eleIntegrityVO.setPid("0");
            netDevIntegrity.add(eleIntegrityVO);
        });
        logicDevList.forEach(item->{
            EleIntegrityVO eleIntegrityVO = new EleIntegrityVO();
            BeanUtil.copyProperties(item,eleIntegrityVO);
            eleIntegrityVO.setInfo(item.getPosition());
            logicAccessList.forEach(item2->{
               if (Objects.equals(item.getDid(),item2.getDid())){
                   if (Objects.equals(item2.getState(), ModelState.ACCESS)){
                       eleIntegrityVO.setComFlag(DataStateEnum.ENABLE.getCode());
                   } else {
                       eleIntegrityVO.setComFlag(DataStateEnum.DELETED.getCode());
                   }
               }
            });
            logicDevIntegrity.add(eleIntegrityVO);
        });
        List<ElePublicDTO> lineList = getLineData(startTime,endTime);
        eleLineList.forEach(item->{
            EleIntegrityVO eleIntegrityVO = new EleIntegrityVO();
            BeanUtil.copyProperties(item,eleIntegrityVO);
            eleIntegrityVO.setInfo(item.getPosition());
            if (!CollectionUtils.isEmpty(lineList)){
                lineList.forEach(item2->{
                    if (Objects.equals(item.getLineId(),item2.getLineId())){
                        eleIntegrityVO.setIntegrity(item2.getData());
                    }
                });
            }
            lineIntegrity.add(eleIntegrityVO);
        });
        dealAverageAndChildrenData(logicDevIntegrity,lineIntegrity,true,startTime,endTime);
        dealAverageAndChildrenData(netDevIntegrity,logicDevIntegrity,false,startTime,endTime);
        return netDevIntegrity;
    }

    private void dealAverageAndChildrenData(List<EleIntegrityVO> targetData, List<EleIntegrityVO> childrenData, boolean isLine,String startTime,String endTime) {
        Map<String, List<EleIntegrityVO>> groupLine = childrenData.stream().collect(Collectors.groupingBy(EleIntegrityVO::getPid));
        targetData = targetData.stream().peek(integrityVO -> {
            if (!CollectionUtils.isEmpty(groupLine.get(integrityVO.getId()))) {
                List<String> lineList = new ArrayList<>();
                List<EleIntegrity> areaList = new ArrayList<>();
                //监测点集合
                List<EleIntegrityVO> integrityVOList = new ArrayList<>();
                if (isLine) {
                    integrityVOList = groupLine.get(integrityVO.getId());
                } else {
                    //子集合，从子集合中拿出所有的监测点集合
                    List<EleIntegrityVO> childIntegrityVOList = groupLine.get(integrityVO.getId());
                    for (EleIntegrityVO vo : childIntegrityVOList) {
                        integrityVOList.addAll(vo.getLineData());
                    }
                }
                integrityVO.setLineData(integrityVOList);
                integrityVO.setChildren(groupLine.get(integrityVO.getId()));
                lineList = integrityVOList.stream().map(EleIntegrityVO::getLineId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(lineList)){
                    //查询结果
                    areaList = getAreaList(startTime,endTime,lineList);
                    if(!CollectionUtils.isEmpty(areaList)){
                        integrityVO.setIntegrity(getAreaData(areaList));
                    }
                }
            }
        }).collect(Collectors.toList());
    }


    /**
     * 数据完整性
     * 监测点(日/月统计)
     * 数据结果已乘以100，作为百分数
     */
    private List<ElePublicDTO> getLineData(String startTime, String endTime) {
        List<ElePublicDTO> result = new ArrayList<>();
        String sql = "SELECT sum(real)/sum(due)*100 AS data FROM ele_integrity where time >='"+startTime+"' and time <= '"+endTime+"' group by line_id tz('Asia/Shanghai')";
        QueryResult sqlResult = influxDbUtils.query(sql);
        List<QueryResult.Series> list = sqlResult.getResults().get(0).getSeries();
        if (!CollectionUtils.isEmpty(list)){
            list.forEach(po -> {
                ElePublicDTO publicDTO = new ElePublicDTO();
                List<List<Object>> valueList = po.getValues();
                String index = po.getTags().get("line_id");
                if (!CollectionUtils.isEmpty(valueList)) {
                    for (List<Object> value : valueList) {
                        //数据完整性 保留二位小数
                        double integrity = value.get(1) == null ? 3.14159 : BigDecimal.valueOf(Double.parseDouble(value.get(1).toString())).setScale(2, RoundingMode.HALF_UP).doubleValue();
                        publicDTO.setLineId(index);
                        publicDTO.setData(Math.min(integrity, 100.00));
                    }
                }
                result.add(publicDTO);
            });
        }
        return result;
    }

    /**
     * 数据完整性
     * 区域(日/月统计)
     */
    private List<EleIntegrity> getAreaList(String startTime, String endTime, List<String> lineList) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("(");
        for (int i = 0; i < lineList.size(); i++) {
            if (lineList.size() - i != 1) {
                stringBuilder.append("line_id = '").append(lineList.get(i)).append("' or ");
            } else {
                stringBuilder.append("line_id = '").append(lineList.get(i)).append("')");
            }
        }
        String sql = "SELECT * FROM ele_integrity where "+stringBuilder+" and time >='"+startTime+"' and time <= '"+endTime+"' tz('Asia/Shanghai')";
        QueryResult sqlResult = influxDbUtils.query(sql);
        InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
        List<EleIntegrity> integrityList = resultMapper.toPOJO(sqlResult, EleIntegrity.class);
        integrityList.forEach(item->{
            item.setTime(item.getTime().plusMillis(TimeUnit.HOURS.toMillis(8)));
        });
        return integrityList;
    }

    /**
     * 根据时间分组，求区域的数据完整性
     */
    private Double getAreaData(List<EleIntegrity> list) {
        double result = 0.0;
        Map<Instant, List<EleIntegrity>> map = list.stream().collect(Collectors.groupingBy(EleIntegrity::getTime));
        for (Instant key : map.keySet()) {
            double data = 0.0;
            List<EleIntegrity> value = map.get(key);
            for (EleIntegrity item : value) {
                double dayData = (double)item.getReal()/item.getDue();
                data = data + dayData;
            }
            //区域某一天的数据完整性
            data = data/value.size();
            //区域时间范围数据完整性之和
            result = result + data;
        }
        return BigDecimal.valueOf(Math.min(result/map.size()*100, 100.00)).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
}
