package com.njcn.harmonic.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.common.config.GeneralInfo;
import com.njcn.common.pojo.dto.SimpleDTO;
import com.njcn.common.pojo.param.StatisticsBizBaseParam;
import com.njcn.device.pq.api.GeneralDeviceInfoClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.api.UserLedgerFeignClient;
import com.njcn.device.pq.enums.LineBaseEnum;
import com.njcn.device.pq.enums.PowerFlagEnum;
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
import com.njcn.device.pq.pojo.vo.LineDetailVO;
import com.njcn.harmonic.mapper.RMpVThdMapper;
import com.njcn.harmonic.mapper.THDistortionMapper;
import com.njcn.harmonic.pojo.THDistortionDetailVO;
import com.njcn.harmonic.pojo.dto.PublicDTO;
import com.njcn.harmonic.pojo.po.RMpVThd;
import com.njcn.harmonic.pojo.vo.RMpVThdVO;
import com.njcn.harmonic.pojo.vo.THDistortionCensusVO;
import com.njcn.harmonic.pojo.vo.THDistortionVO;
import com.njcn.harmonic.service.THDistortionService;
import com.njcn.harmonic.utils.PubUtils;
import com.njcn.supervision.pojo.param.user.UserReportParam;
import com.njcn.supervision.pojo.vo.user.UserLedgerVO;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: chenchao
 * @date: 2022/03/11 10:09
 * @Description: <描述>
 */
@Service
@RequiredArgsConstructor
public class THDistortionServiceImpl implements THDistortionService {

    private final GeneralInfo generalInfo;
    private final GeneralDeviceInfoClient generalDeviceInfoClient;
    private final THDistortionMapper thDistortionMapper;
    private final RMpVThdMapper rMpVThdMapper;
    private final LineFeignClient lineFeignClient;
    private final UserLedgerFeignClient userLedgerFeignClient;
    /**
     *
     */
    @Value("${version.used:master}")
    private String versionUsed;

    @Override
    public List<THDistortionVO> getTHDistortionData(DeviceInfoParam.BusinessParam thDistortionParam, Integer nodeType) {
        List<THDistortionVO> thDistortionVOS = new ArrayList<>();

        //按照条件获取实际运行终端综合信息
        DeviceInfoParam deviceInfoParam = new DeviceInfoParam(thDistortionParam.getStatisticalType(), thDistortionParam.getDeptIndex(), generalInfo.getMicroServiceName(), thDistortionParam.getScale(), thDistortionParam.getManufacturer(), thDistortionParam.getLoadType());
        List<GeneralDeviceDTO> deviceList = generalDeviceInfoClient.getPracticalRunDeviceInfo(deviceInfoParam).getData();
        Map<String, UserLedgerVO> userLedgerVOMap = new HashMap<>();
        if (thDistortionParam.isUserLedger()) {
            List<UserLedgerVO> userLedgerVOList = userLedgerFeignClient.selectUserList(new UserReportParam()).getData();
            userLedgerVOMap.putAll(userLedgerVOList.stream().collect(Collectors.toMap(UserLedgerVO::getId, Function.identity())));
        }


        //组装监测点Top层集合
        for (GeneralDeviceDTO generalDeviceDTO : deviceList) {
            List<String> lineIndexes = generalDeviceDTO.getLineIndexes();
            if (CollectionUtils.isEmpty(lineIndexes)) {
                continue;
            }
            THDistortionVO thDistortionVO = new THDistortionVO();
            thDistortionVO.setId(generalDeviceDTO.getIndex());
            thDistortionVO.setName(generalDeviceDTO.getName());

            //查找畸变率
            List<PublicDTO> condition = getCondition(lineIndexes, thDistortionParam.getSearchBeginTime(), thDistortionParam.getSearchEndTime());
            thDistortionVO.setDistortion(roundHalfUp(condition.stream().mapToDouble(PublicDTO::getData).average().orElse(3.14159)));
            //组装父级数据树
            List<THDistortionVO> treeList = getTreeData(lineIndexes, condition, userLedgerVOMap, thDistortionParam.getPowerFlag());
            thDistortionVO.setChildren(treeList);
            thDistortionVOS.add(thDistortionVO);
        }
        if (nodeType == 1) {
            thDistortionVOS.forEach(data -> {
                if (CollUtil.isNotEmpty(data.getChildren())) {
                    //市
                    List<THDistortionVO> sub = data.getChildren().stream().flatMap(dto -> dto.getChildren().stream()).collect(Collectors.toList());
                    sub.forEach(x -> {
                        x.setChildren(new ArrayList<>());
                    });
                    data.setChildren(sub);
                }
            });
        }
        return thDistortionVOS;
    }

    @Override
    public THDistortionCensusVO getTHDistortionCensus(DeviceInfoParam.BusinessParam thDistortionCensusParam) {
        List<THDistortionVO> thDistortionVOS = getTHDistortionData(thDistortionCensusParam, 0);

        THDistortionCensusVO distortionCensusVO = new THDistortionCensusVO();
//        thDistortionCensusParam.setServerName(generalInfo.getMicroServiceName());
//        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceInfoClient.getPracticalRunDeviceInfo(thDistortionCensusParam).getData();
        List<String> type = new ArrayList<>();
        List<Double> single = new ArrayList<>();
        if (!CollectionUtils.isEmpty(thDistortionVOS)) {
            for (THDistortionVO thDistortionVO : thDistortionVOS) {
//                List<String> lineIndexes = generalDeviceDTO.getLineIndexes();
//                if (CollectionUtils.isEmpty(lineIndexes)) {
//                    continue;
//                }
//                type.add(thDistortionVO.getName() + "\n(" + seekLineNum(thDistortionVO) + ")");
                type.add(thDistortionVO.getName());
//                List<PublicDTO> condition = getCondition(lineIndexes, thDistortionCensusParam.getSearchBeginTime(), thDistortionCensusParam.getSearchEndTime());
                single.add(thDistortionVO.getDistortion());
            }
            distortionCensusVO.setType(type);
            distortionCensusVO.setSingle(single);
        }
        return distortionCensusVO;
    }

    /**
     * 递归出有多少个测点
     *
     * @param thDistortionVO 最上层的信息
     */
    private int seekLineNum(THDistortionVO thDistortionVO) {
        List<THDistortionVO> children = thDistortionVO.getChildren();
        // 如果没有子节点，说明当前就是最底层节点，计数1
        if (children == null || children.isEmpty()) {
            return 1;
        }
        // 如果有子节点，递归计算所有子节点的最底层节点总数
        int total = 0;
        for (THDistortionVO child : children) {
            total += seekLineNum(child);
        }
        return total;
    }

    /**
     * @param statisticsBizBaseParam
     * @Description: 谐波总畸变率前十列表
     * @Param: [statisticsBizBaseParam]
     * @return: java.util.List<com.njcn.harmonic.pojo.vo.RMpVThdVO>
     * @Author: clam
     * @Date: 2022/10/10
     */
    @Override
    public List<RMpVThdVO> getTHDTopTenData(StatisticsBizBaseParam statisticsBizBaseParam, Integer topNum) {

        List<RMpVThdVO> rMpVThdVOList = new ArrayList<>();
        DeviceInfoParam deviceInfoParam = new DeviceInfoParam();
        deviceInfoParam.setDeptIndex(statisticsBizBaseParam.getId());
        deviceInfoParam.setStatisticalType(new SimpleDTO());
        deviceInfoParam.setServerName(generalInfo.getMicroServiceName());
        deviceInfoParam.setPowerFlag(2);
        deviceInfoParam.setMonitorFlag(2);
        /*获取按部门分类的实际所有终端综合信息*/
        List<GeneralDeviceDTO> deviceList = generalDeviceInfoClient.getPracticalAllDeviceInfoAsDept(deviceInfoParam).getData();
        /*监测点ID扁平化*/
        List<String> collect = deviceList.stream().map(GeneralDeviceDTO::getLineIndexes).flatMap(Collection::stream).distinct().collect(Collectors.toList());
        QueryWrapper<RMpVThd> wrapper = new QueryWrapper<>();
        wrapper.select("measurement_point_id", "max(v_thd) as v_thd")
                .in("measurement_point_id", collect)
                .between("data_date", statisticsBizBaseParam.getStartTime(), statisticsBizBaseParam.getEndTime())
                .eq("data_type", 0).groupBy("measurement_point_id")
                .orderByDesc("v_thd");
        List<RMpVThd> rMpVThdList = rMpVThdMapper.selectList(wrapper);
        rMpVThdVOList = rMpVThdList.stream().limit(topNum).map(rMpVThd -> {
            RMpVThdVO rMpVThdVO = new RMpVThdVO();
            BeanUtils.copyProperties(rMpVThd, rMpVThdVO);
            /*查询监测点详情获取名称*/
            LineDetailVO data = lineFeignClient.getLineSubGdDetail(rMpVThd.getMeasurementPointId()).getData();
            rMpVThdVO.setName(data.getLineName());
            rMpVThdVO.setSubStationName(data.getSubName());
            return rMpVThdVO;
        }).collect(Collectors.toList());

        return rMpVThdVOList;
    }

    @Override
    public List<THDistortionDetailVO> getTHDistortionTableData(DeviceInfoParam.BusinessParam steadyParam) {
        List<THDistortionDetailVO> thDistortionDetailVOList = new ArrayList<>();
        //获取终端台账类信息
        List<GeneralDeviceDTO> deviceDataList = generalDeviceInfoClient.getPracticalRunDeviceInfo(steadyParam).getData();

        //收集所有lineIndexes并去重
        List<String> lineIdList = deviceDataList.stream()
                .filter(generalDeviceDTO -> CollectionUtil.isNotEmpty(generalDeviceDTO.getLineIndexes()))
                .flatMap(generalDeviceDTO -> generalDeviceDTO.getLineIndexes().stream())
                .distinct()
                .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(lineIdList)) {
            return thDistortionDetailVOList;
        }

        //获取畸变率数据
        List<PublicDTO> distortionData = getCondition(lineIdList, steadyParam.getSearchBeginTime(), steadyParam.getSearchEndTime());
        Map<String, PublicDTO> distortionMap = distortionData.stream()
                .collect(Collectors.toMap(PublicDTO::getId, Function.identity()));

        //获取监测点集合
        List<THDistortionVO> monitorList = thDistortionMapper.getLineData(lineIdList);

        //获取所有监测点信息信息
        List<LineDetailVO.Detail> lineInfoByIds = lineFeignClient.getLineDetailByIds(lineIdList).getData();
        Map<String, LineDetailVO.Detail> lineDetailMap = lineInfoByIds.stream()
                .collect(Collectors.toMap(LineDetailVO.Detail::getLineId, Function.identity()));

        //组装列表数据
        for (THDistortionVO monitor : monitorList) {
            THDistortionDetailVO detailVO = new THDistortionDetailVO();

            //填充监测点详细信息
            LineDetailVO.Detail lineDetail = lineDetailMap.get(monitor.getId());
            if (lineDetail != null) {
                detailVO.setCity(lineDetail.getDeptName());
                detailVO.setCompany(lineDetail.getGdName());
                detailVO.setSubStation(lineDetail.getSubName());
                detailVO.setDeviceId(lineDetail.getDevId());
                detailVO.setDeviceName(lineDetail.getDevName());
                detailVO.setManufacturer(lineDetail.getManufacturer());
                detailVO.setIp(lineDetail.getIp());
                detailVO.setLineName(lineDetail.getLineName());
            }

            //填充畸变率数据
            if (distortionMap.containsKey(monitor.getId())) {
                detailVO.setDistortion(distortionMap.get(monitor.getId()).getData());
            }

            thDistortionDetailVOList.add(detailVO);
        }

        //先按变电站排序，再按地市排序
        thDistortionDetailVOList.sort(Comparator
                .comparing(THDistortionDetailVO::getSubStation, Comparator.nullsLast(String::compareTo))
                .thenComparing(THDistortionDetailVO::getCity, Comparator.nullsLast(String::compareTo)));

        return thDistortionDetailVOList;
    }


    /**
     * 计算父级畸变率
     */
    private void setFatherDistortion(List<THDistortionVO> list) {
        list.forEach(thDistortionVO -> {
            List<THDistortionVO> children = thDistortionVO.getChildren();
            List<THDistortionVO> tempList = children.stream().filter(child -> !Objects.equals(child.getDistortion(), 3.14159)).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(tempList)) {
                thDistortionVO.setDistortion(roundHalfUp(tempList.stream().mapToDouble(THDistortionVO::getDistortion).average().orElse(3.14159)));
            } else {
                thDistortionVO.setDistortion(3.14159);
            }
        });
    }

    /**
     * 计算供电公司畸变率
     */
    private void setPowerDistortion(List<THDistortionVO> list) {
        List<THDistortionVO> result = new ArrayList<>();
        list.forEach(item -> {
            List<THDistortionVO> children = item.getChildren();
            children.forEach(item2 -> {
                result.addAll(item2.getChildren());
            });
            if (CollectionUtil.isNotEmpty(result)) {
                item.setDistortion(roundHalfUp(result.stream().filter(child -> !Objects.equals(child.getDistortion(), 3.14159)).mapToDouble(THDistortionVO::getDistortion).average().orElse(3.14159)));
            } else {
                item.setDistortion(3.14159);
            }
        });
    }

    /**
     * 组装树层级
     */
    private List<THDistortionVO> getChildCategoryList(THDistortionVO item, List<THDistortionVO> child) {
        return child.stream().filter(allItem -> allItem.getPid().equals(item.getId())).collect(Collectors.toList());
    }

    private void setChildesList(List<THDistortionVO> item, List<THDistortionVO> childes, List<THDistortionVO> userList) {
        //groupLine变电站索引和监测点集合
        Map<String, List<THDistortionVO>> groupLine;
        groupLine = childes.stream().collect(Collectors.groupingBy(thDistortionVO -> {
            String[] pid = thDistortionVO.getPidS().split(StrUtil.COMMA);
            return pid[LineBaseEnum.SUB_LEVEL.getCode()];
        }));

        Map<String, List<THDistortionVO>> userMap = userList.stream().collect(Collectors.groupingBy(THDistortionVO::getPid));
        item.forEach(thDistortionVO -> {
            List<THDistortionVO> temList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(groupLine.get(thDistortionVO.getId()))) {
                temList.addAll(groupLine.get(thDistortionVO.getId()));
            }
            if (userMap.containsKey(thDistortionVO.getId())) {
                temList.addAll(userMap.get(thDistortionVO.getId()));
            }
            thDistortionVO.setChildren(temList);
        });
    }

    /**
     * 获取父级每层数据
     */
    private List<THDistortionVO> getTreeData(List<String> lineIndexes, List<PublicDTO> condition, Map<String, UserLedgerVO> userLedgerVOMap, Integer powerFlag) {
        //监测点集合
        List<THDistortionVO> monitorList = thDistortionMapper.getLineData(lineIndexes);
        Map<String, PublicDTO> map = condition.stream().collect(Collectors.toMap(PublicDTO::getId, Function.identity()));
        for (THDistortionVO thDistortionVO : monitorList) {
            if (map.containsKey(thDistortionVO.getId())) {
                thDistortionVO.setDistortion(map.get(thDistortionVO.getId()).getData());
            }
        }

        List<THDistortionVO> userLedgerList = new ArrayList<>();
        List<THDistortionVO> powerLedgerList = new ArrayList<>();
        if (Objects.equals(PowerFlagEnum.NO_GRID_SIDE.getCode(), powerFlag)) {
            userLedgerList = monitorList.stream().filter(it -> StrUtil.isNotBlank(it.getObjId())).collect(Collectors.toList());
        } else if (Objects.equals(PowerFlagEnum.GRID_SIDE.getCode(), powerFlag)) {
            powerLedgerList = monitorList.stream().filter(it -> StrUtil.isBlank(it.getObjId())).collect(Collectors.toList());
        } else {
            userLedgerList = monitorList.stream().filter(it -> StrUtil.isNotBlank(it.getObjId())).collect(Collectors.toList());
            powerLedgerList = monitorList.stream().filter(it -> StrUtil.isBlank(it.getObjId())).collect(Collectors.toList());
        }
        List<THDistortionVO> userTemList = new ArrayList<>();
        if (CollUtil.isNotEmpty(userLedgerList)) {
            Map<String, List<THDistortionVO>> objMap = userLedgerList.stream().collect(Collectors.groupingBy(THDistortionVO::getObjId));
            objMap.forEach((obj, list) -> {
                THDistortionVO thDistortionVO = new THDistortionVO();
                if (userLedgerVOMap.containsKey(obj)) {
                    UserLedgerVO userLedgerVO = userLedgerVOMap.get(obj);
                    thDistortionVO.setId(userLedgerVO.getId());
                    thDistortionVO.setName(userLedgerVO.getProjectName());
                    thDistortionVO.setPid(userLedgerVO.getStationId());
                    thDistortionVO.setDistortion(list.stream().filter(it -> it.getDistortion() != 3.14159).mapToDouble(THDistortionVO::getDistortion).average().orElse(3.14159));
                    thDistortionVO.setChildren(list);
                    userTemList.add(thDistortionVO);
                }
            });
        }

        //母线集合
        //  List<THDistortionVO> busBarList = thDistortionMapper.getLineInfoByList(monitorList.stream().map(THDistortionVO::getPid).distinct().collect(Collectors.toList()));
        //终端集合
        //List<THDistortionVO> deviceList = thDistortionMapper.getLineInfoByList(busBarList.stream().map(THDistortionVO::getPid).distinct().collect(Collectors.toList()));
        //变电站集合
        List<THDistortionVO> substationList = thDistortionMapper.getLineInfoByList(monitorList.stream().map(it -> it.getPidS().split(StrUtil.COMMA)[LineBaseEnum.SUB_LEVEL.getCode()]).distinct().collect(Collectors.toList()));
        if (!CollectionUtils.isEmpty(monitorList)) {
            setChildesList(substationList, powerLedgerList, userTemList);
            setFatherDistortion(substationList);
            if ("liaoning".equals(versionUsed)) {
                return substationList;
            } else {
                //供电公司集合
                List<THDistortionVO> powerCompanyList = thDistortionMapper.getLineInfoByList(monitorList.stream().map(it -> it.getPidS().split(StrUtil.COMMA)[LineBaseEnum.GD_LEVEL.getCode()]).distinct().collect(Collectors.toList()));
                powerCompanyList = powerCompanyList.stream().peek(item -> item.setChildren(getChildCategoryList(item, substationList))).collect(Collectors.toList());
                setPowerDistortion(powerCompanyList);
                return powerCompanyList;
            }
        }
        return new ArrayList<>();
    }

    /**
     * 四舍五入保留两位小数
     */
    private Double roundHalfUp(double num) {
        if (num == 3.14159) {
            return num;
        }
        BigDecimal b = new BigDecimal(num);
        //保留2位小数
        return PubUtils.dataLimits(b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
    }


    /**
     * influxDB查询畸变率
     *
     * @param lineIndexes
     * @param startTime
     * @param endTime
     */
    private List<PublicDTO> getCondition(List<String> lineIndexes, String startTime, String endTime) {
        List<PublicDTO> publicDTOList = new ArrayList<>();
        //数据库查询
        QueryWrapper<RMpVThd> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("max(v_thd) vThd,measurement_point_id").lambda()
                .in(RMpVThd::getMeasurementPointId, lineIndexes)
                .ge(StrUtil.isNotBlank(startTime), RMpVThd::getDataDate, DateUtil.beginOfDay(DateUtil.parse(startTime)))
                .le(StrUtil.isNotBlank(endTime), RMpVThd::getDataDate, DateUtil.endOfDay(DateUtil.parse(endTime)))
                .eq(RMpVThd::getDataType, 0).groupBy(RMpVThd::getMeasurementPointId);

        List<RMpVThd> info = rMpVThdMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(info)) {
            info.forEach(item -> {
                PublicDTO publicDTO = new PublicDTO();
                publicDTO.setId(item.getMeasurementPointId());
                publicDTO.setData(item.getVThd());
                publicDTOList.add(publicDTO);
            });
        }
        return publicDTOList;
    }


}
