package com.njcn.harmonic.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.common.config.GeneralInfo;
import com.njcn.device.pq.api.GeneralDeviceInfoClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.enums.LineBaseEnum;
import com.njcn.device.pq.pojo.dto.GeneralDeviceDTO;
import com.njcn.device.pq.pojo.param.DeviceInfoParam;
import com.njcn.device.pq.pojo.param.LineBaseQueryParam;
import com.njcn.device.pq.pojo.param.OnlineRateParam;
import com.njcn.device.pq.pojo.vo.AreaLineInfoVO;
import com.njcn.device.pq.pojo.vo.RStatIntegrityVO;
import com.njcn.harmonic.mapper.IntegrityMapper;
import com.njcn.harmonic.pojo.dto.PublicDTO;
import com.njcn.harmonic.pojo.vo.IntegrityIconVO;
import com.njcn.harmonic.pojo.vo.IntegrityVO;
import com.njcn.harmonic.service.IntegrityService;
import com.njcn.poi.excel.ExcelUtil;
import com.njcn.poi.pojo.bo.BaseLineExcelBody;
import com.njcn.poi.pojo.bo.BaseLineProExcelBody;
import com.njcn.poi.util.PoiUtil;
import com.njcn.system.pojo.enums.StatisticsEnum;
import com.njcn.web.utils.RequestUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.Collator;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类的介绍：
 *
 * @author xuyang
 * @version 1.0.0
 * @date 2021/12/31 9:50
 */
@Slf4j
@Service
@AllArgsConstructor
public class IntegrityServiceImpl implements IntegrityService {

    private final IntegrityMapper integrityMapper;

    private final GeneralDeviceInfoClient generalDeviceInfoClient;

    private final GeneralInfo generalInfo;

    private final LineFeignClient lineFeignClient;

    @Override
    public List<IntegrityVO> getIntegrityData(DeviceInfoParam.BusinessParam integrityParam) {
        List<IntegrityVO> result = new ArrayList<>();
        integrityParam.setServerName(generalInfo.getMicroServiceName());
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceInfoClient.getPracticalRunDeviceInfo(integrityParam).getData();
        if (!CollectionUtils.isEmpty(generalDeviceDTOList)) {
            for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
                List<String> lineIndexes = generalDeviceDTO.getLineIndexes();
                if (CollectionUtils.isEmpty(lineIndexes)) {
                    continue;
                }
                //初始化返回结果integrityTemp
                IntegrityVO integrityTemp = new IntegrityVO();
                integrityTemp.setName(generalDeviceDTO.getName());
                //根据监测点查询数据完整性
                List<PublicDTO> integrityData = getCondition(lineIndexes, integrityParam.getSearchBeginTime(), integrityParam.getSearchEndTime());
                //查询监测点、变电站、供电公司、区域的基础信息
                List<IntegrityVO> lineBaseInfo = integrityMapper.getIntegrityData(lineIndexes);
                List<IntegrityVO> subBaseInfo = integrityMapper.getSubstationInfoByList(generalDeviceDTO.getSubIndexes());
                List<IntegrityVO> gdBaseInfo = integrityMapper.getLineInfoByList(generalDeviceDTO.getGdIndexes());
                List<IntegrityVO> areaInfo = integrityMapper.getProviceInfoByList(gdBaseInfo.stream().map(IntegrityVO::getPid).distinct().collect(Collectors.toList()));
                //监测点数据完整性赋值
                if (!CollectionUtils.isEmpty(integrityData)) {
                    for (IntegrityVO integrityVO : lineBaseInfo) {
                        for (PublicDTO integrityDatum : integrityData) {
                            if (integrityVO.getId().equals(integrityDatum.getId())) {
                                integrityVO.setIntegrityData(integrityDatum.getData());
                                break;
                            }
                        }
                    }
                }
                //处理变电站
                dealAverageAndChildrenData(subBaseInfo, lineBaseInfo, true);
                //处理供电公司
                dealAverageAndChildrenData(gdBaseInfo, subBaseInfo, false);
                /**
                 * ----------------------------------
                 * 处理顶层数据
                 * xy
                 */
                integrityTemp.setLineData(lineBaseInfo);
                double averageData = lineBaseInfo.stream().filter(integrityVO1 -> integrityVO1.getIntegrityData() != 3.14159)
                        .mapToDouble(IntegrityVO::getIntegrityData)
                        .average()
                        .orElse(3.14159);
                integrityTemp.setIntegrityData(averageData);
                /**
                 * 结束
                 * ----------------------------------
                 */
                if (integrityParam.getStatisticalType().getCode().equalsIgnoreCase(StatisticsEnum.POWER_NETWORK.getCode())) {
                    integrityTemp.setChildren(gdBaseInfo);
                } else {
                    //还需要额外处理省会
                    dealAverageAndChildrenData(areaInfo, gdBaseInfo, false);
                    integrityTemp.setChildren(areaInfo);
                }
                result.add(integrityTemp);
            }
        }
        return result;
    }

    /**
     * 处理平均值以及子节点集合
     */
    private void dealAverageAndChildrenData(List<IntegrityVO> targetData, List<IntegrityVO> childrenData, boolean isLine) {
        Map<String, List<IntegrityVO>> groupLine;
        if (isLine) {
            groupLine = childrenData.stream().collect(Collectors.groupingBy(integrityVO -> {
                String[] pid = integrityVO.getPidS().split(",");
                return pid[LineBaseEnum.SUB_LEVEL.getCode()];
            }));
        } else {
            groupLine = childrenData.stream().collect(Collectors.groupingBy(IntegrityVO::getPid));
        }
        targetData = targetData.stream().peek(integrityVO -> {
            if (!CollectionUtils.isEmpty(groupLine.get(integrityVO.getId()))) {
                //监测点集合
                List<IntegrityVO> integrityVOList = new ArrayList<>();
                if (isLine) {
                    integrityVOList = groupLine.get(integrityVO.getId());
                } else {
                    //子集合，从子集合中拿出所有的监测点集合
                    List<IntegrityVO> childIntegrityVOList = groupLine.get(integrityVO.getId());
                    for (IntegrityVO vo : childIntegrityVOList) {
                        integrityVOList.addAll(vo.getLineData());
                    }
                }
                integrityVO.setLineData(integrityVOList);
                //通过所有监测点的完整性求平均值
                double averageData = integrityVOList.stream().filter(integrityVO1 -> integrityVO1.getIntegrityData() != 3.14159)
                        .mapToDouble(IntegrityVO::getIntegrityData)
                        .average()
                        .orElse(3.14159);
                integrityVO.setIntegrityData(averageData);

                integrityVO.setChildren(groupLine.get(integrityVO.getId()));
            }
        }).collect(Collectors.toList());
    }

    @Override
    public List<IntegrityIconVO> getIntegrityIcon(DeviceInfoParam.CompareBusinessParam integrityIconParam) {
        integrityIconParam.setServerName(generalInfo.getMicroServiceName());
        List<GeneralDeviceDTO> generalDeviceDTOList = generalDeviceInfoClient.getPracticalRunDeviceInfo(integrityIconParam).getData();
        /*List<String> type = new ArrayList<>();
        List<Double> single = new ArrayList<>(),
                ratio = new ArrayList<>();*/
        List<IntegrityIconVO> out = new ArrayList<>();
        if (!CollectionUtils.isEmpty(generalDeviceDTOList)) {
            for (GeneralDeviceDTO generalDeviceDTO : generalDeviceDTOList) {
                IntegrityIconVO outParam = new IntegrityIconVO();
                List<String> lineIndexes = generalDeviceDTO.getLineIndexes();
                if (CollectionUtils.isEmpty(lineIndexes)) {
                    continue;
                }
                outParam.setType(generalDeviceDTO.getName());
                //根据监测点查询数据完整性
                List<PublicDTO> integrityData = getCondition(lineIndexes, integrityIconParam.getSearchBeginTime(), integrityIconParam.getSearchEndTime());

                double temSingle = integrityData.stream().mapToDouble(PublicDTO::getData).average().orElse(3.14159);
                outParam.setSingle(temSingle == 3.14159 ? temSingle :NumberUtil.round(temSingle, 2).doubleValue());
                //如果存在需要比较的时间，再获取对应数据
                if (StrUtil.isNotBlank(integrityIconParam.getPeriodBeginTime()) && StrUtil.isNotBlank(integrityIconParam.getPeriodEndTime())) {
                    List<PublicDTO> compareData = getCondition(lineIndexes, integrityIconParam.getPeriodBeginTime(), integrityIconParam.getPeriodEndTime());
                    double tem = compareData.stream().mapToDouble(PublicDTO::getData).average().orElse(3.14159);
                    outParam.setRatio(tem == 3.14159 ? tem : NumberUtil.round(tem, 2).doubleValue());
                }
                out.add(outParam);
            }
        }
        out.sort(new Comparator<IntegrityIconVO>() {
            @Override
            public int compare(IntegrityIconVO o1, IntegrityIconVO o2) {
                Comparator<Object> com = Collator.getInstance(Locale.CHINA);
                return com.compare(o1.getType(), o2.getType());
            }
        });
        return out;
    }

    /**
     * 组装需要下载excel的数据
     *
     * @param integrityParam 数据完整性参数
     * @param methodDescribe 报表名称描述
     */
    @Override
    public String exportIntegrityData(DeviceInfoParam.BusinessParam integrityParam, String methodDescribe) {
        String fileName = methodDescribe + CharUtil.UNDERLINE + integrityParam.getStatisticalType().getName() + ".xlsx";
        String targetDir = generalInfo.getBusinessTempPath() + File.separator + RequestUtil.getUserIndex();
        log.error("文件路径" + targetDir);
        log.error("文件名" + fileName);
        File parentDir = new File(targetDir);
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        File excel = new File(targetDir, fileName);
        List<IntegrityVO> integrityData = getIntegrityData(integrityParam);
        if (integrityParam.getStatisticalType().getCode().equalsIgnoreCase(StatisticsEnum.POWER_NETWORK.getCode())) {
            List<BaseLineExcelBody> excelBodies = new ArrayList<>();
            if (!CollectionUtils.isEmpty(integrityData)) {
                for (IntegrityVO integrityVOLoop : integrityData) {
                    BaseLineExcelBody baseLineExcelBody = new BaseLineExcelBody();
                    baseLineExcelBody.setStatisticsName(integrityVOLoop.getName() + PoiUtil.dealPOIData(integrityVOLoop.getIntegrityData()));
                    addChildExcelData(excelBodies, baseLineExcelBody, integrityVOLoop.getChildren());
                }
            }
            ExcelUtil.exportExcelWithTargetFile(excel, integrityParam.getStatisticalType().getName(), methodDescribe, BaseLineExcelBody.class, excelBodies);
        } else {
            //还需要额外处理省会
            List<BaseLineProExcelBody> excelBodies = new ArrayList<>();
            if (!CollectionUtils.isEmpty(integrityData)) {
                for (IntegrityVO integrityVOLoop : integrityData) {
                    BaseLineProExcelBody baseLineProExcelBody = new BaseLineProExcelBody();
                    baseLineProExcelBody.setStatisticsName(integrityVOLoop.getName() + PoiUtil.dealPOIData(integrityVOLoop.getIntegrityData()));
                    addChildProExcelData(excelBodies, baseLineProExcelBody, integrityVOLoop.getChildren());
                }
            }
            ExcelUtil.exportExcelWithTargetFile(excel, integrityParam.getStatisticalType().getName(), methodDescribe, BaseLineProExcelBody.class, excelBodies);
        }
        return FileUtil.getAbsolutePath(excel);
    }

    /**
     * 递归获取子集数据，网络拓扑特殊处理项
     *
     * @param excelBodies         表格集合
     * @param baseLineExcelBody   父级表格数据
     * @param childrenIntegrityVO 子集表格数据
     */
    private void addChildExcelData(List<BaseLineExcelBody> excelBodies, BaseLineExcelBody baseLineExcelBody, List<IntegrityVO> childrenIntegrityVO) {
        if (!CollectionUtils.isEmpty(childrenIntegrityVO)) {
            for (IntegrityVO integrityVO : childrenIntegrityVO) {
                LineBaseEnum lineBaseEnum = LineBaseEnum.getLineBaseEnumByCode(integrityVO.getLevel());
                BaseLineExcelBody fatherBaseLineExcelBody;
                List<IntegrityVO> children = integrityVO.getChildren();
                switch (lineBaseEnum) {
                    case GD_LEVEL:
                        BaseLineExcelBody gdBaseLineExcelBody = new BaseLineExcelBody();
                        BeanUtil.copyProperties(baseLineExcelBody, gdBaseLineExcelBody);
                        gdBaseLineExcelBody.setGdName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        fatherBaseLineExcelBody = gdBaseLineExcelBody;
                        break;
                    case SUB_LEVEL:
                        BaseLineExcelBody subBaseLineExcelBody = new BaseLineExcelBody();
                        BeanUtil.copyProperties(baseLineExcelBody, subBaseLineExcelBody);
                        subBaseLineExcelBody.setSubName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        subBaseLineExcelBody.setSubScale(integrityVO.getVoltageLevel());
                        fatherBaseLineExcelBody = subBaseLineExcelBody;
                        break;
                    default:
                        //因为只有供电公司、变电站，下面就是监测点，所以default默认为监测点层级
                        BaseLineExcelBody lineBaseLineExcelBody = new BaseLineExcelBody();
                        BeanUtil.copyProperties(baseLineExcelBody, lineBaseLineExcelBody);
                        lineBaseLineExcelBody.setLineName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        lineBaseLineExcelBody.setDeviceName(integrityVO.getDeviceName());
                        lineBaseLineExcelBody.setNetworkParam(integrityVO.getNetworkParam());
                        lineBaseLineExcelBody.setFactoryName(integrityVO.getFactoryName());
                        lineBaseLineExcelBody.setComState(integrityVO.getState());
                        lineBaseLineExcelBody.setTime(integrityVO.getTime());
                        lineBaseLineExcelBody.setSubvScale(integrityVO.getVoltageLevel());
                        excelBodies.add(lineBaseLineExcelBody);
                        fatherBaseLineExcelBody = lineBaseLineExcelBody;
                        break;
                }
                addChildExcelData(excelBodies, fatherBaseLineExcelBody, children);
            }
        }
    }

    /**
     * 递归获取子集数据，电压等级、终端厂家、干扰源类型有额外的省公司名称
     *
     * @param excelBodies          表格集合
     * @param baseLineProExcelBody 父级表格数据
     * @param childrenIntegrityVO  子集表格数据
     */
    private void addChildProExcelData(List<BaseLineProExcelBody> excelBodies, BaseLineProExcelBody baseLineProExcelBody, List<IntegrityVO> childrenIntegrityVO) {
        if (!CollectionUtils.isEmpty(childrenIntegrityVO)) {
            for (IntegrityVO integrityVO : childrenIntegrityVO) {
                LineBaseEnum lineBaseEnum = LineBaseEnum.getLineBaseEnumByCode(integrityVO.getLevel());
                BaseLineProExcelBody fatherBaseLineProExcelBody;
                List<IntegrityVO> children = integrityVO.getChildren();
                switch (lineBaseEnum) {
                    case PROVINCE_LEVEL:
                        BaseLineProExcelBody provinceBaseLineProExcelBody = new BaseLineProExcelBody();
                        BeanUtil.copyProperties(baseLineProExcelBody, provinceBaseLineProExcelBody);
                        provinceBaseLineProExcelBody.setProvincialName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        fatherBaseLineProExcelBody = provinceBaseLineProExcelBody;
                        break;
                    case GD_LEVEL:
                        BaseLineProExcelBody gdBaseLineProExcelBody = new BaseLineProExcelBody();
                        BeanUtil.copyProperties(baseLineProExcelBody, gdBaseLineProExcelBody);
                        gdBaseLineProExcelBody.setGdName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        fatherBaseLineProExcelBody = gdBaseLineProExcelBody;
                        break;
                    case SUB_LEVEL:
                        BaseLineProExcelBody subBaseLineProExcelBody = new BaseLineProExcelBody();
                        BeanUtil.copyProperties(baseLineProExcelBody, subBaseLineProExcelBody);
                        subBaseLineProExcelBody.setSubName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        subBaseLineProExcelBody.setSubScale(integrityVO.getVoltageLevel());
                        fatherBaseLineProExcelBody = subBaseLineProExcelBody;
                        break;
                    default:
                        //因为只有供电公司、变电站，下面就是监测点，所以default默认为监测点层级
                        BaseLineProExcelBody lineBaseLineProExcelBody = new BaseLineProExcelBody();
                        BeanUtil.copyProperties(baseLineProExcelBody, lineBaseLineProExcelBody);
                        lineBaseLineProExcelBody.setLineName(integrityVO.getName() + PoiUtil.dealPOIData(integrityVO.getIntegrityData()));
                        lineBaseLineProExcelBody.setDeviceName(integrityVO.getDeviceName());
                        lineBaseLineProExcelBody.setNetworkParam(integrityVO.getNetworkParam());
                        lineBaseLineProExcelBody.setFactoryName(integrityVO.getFactoryName());
                        lineBaseLineProExcelBody.setComState(integrityVO.getState());
                        lineBaseLineProExcelBody.setTime(integrityVO.getTime());
                        lineBaseLineProExcelBody.setSubvScale(integrityVO.getVoltageLevel());
                        fatherBaseLineProExcelBody = lineBaseLineProExcelBody;
                        excelBodies.add(lineBaseLineProExcelBody);
                        break;
                }
                addChildProExcelData(excelBodies, fatherBaseLineProExcelBody, children);
            }
        }
    }


    private List<PublicDTO> getCondition(List<String> lineList, String startTime, String endTime) {
        List<PublicDTO> integrityList = new ArrayList<>();
        OnlineRateParam param = new OnlineRateParam();
        param.setIds(lineList);
        param.setStartTime(DateUtil.beginOfDay(DateUtil.parse(startTime)).toString());
        param.setEndTime(DateUtil.endOfDay(DateUtil.parse(endTime)).toString());
        List<RStatIntegrityVO> data = lineFeignClient.getOnIntegrityByIds(param).getData();
        if (!CollectionUtils.isEmpty(data)) {
            data.forEach(po -> {
                PublicDTO publicDTO = new PublicDTO();
                //数据完整性 保留四位小数
                Double integrity = po.getIntegrityRate() == null ? 3.14159 : BigDecimal.valueOf(Double.parseDouble(po.getIntegrityRate().toString())).setScale(2, RoundingMode.HALF_UP).doubleValue();
                publicDTO.setId(po.getLineIndex());
                publicDTO.setData((integrity > 100.00) ? 100.00 : integrity);
                integrityList.add(publicDTO);
            });
        }
        return integrityList;


    }

}
