package com.njcn.csharmonic.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsLedgerFeignClient;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.enums.AlgorithmResponseEnum;
import com.njcn.csdevice.pojo.dto.CsEquipmentDeliveryDTO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csdevice.utils.ReflectUtils;
import com.njcn.csharmonic.param.CommonStatisticalQueryParam;
import com.njcn.csharmonic.param.FrequencyStatisticalQueryParam;
import com.njcn.csharmonic.param.ThdDataQueryParm;
import com.njcn.csharmonic.pojo.po.PqGovernPlan;
import com.njcn.csharmonic.pojo.vo.ThdDataVO;
import com.njcn.csharmonic.service.IPqGovernPlanService;
import com.njcn.csharmonic.service.StableDataService;
import com.njcn.csharmonic.util.InfluxDbParamUtil;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import com.njcn.influx.pojo.bo.CommonQueryParam;
import com.njcn.influx.pojo.dto.StatisticalDataDTO;
import com.njcn.influx.pojo.po.HarmonicRatioData;
import com.njcn.influx.pojo.po.PowerQualityData;
import com.njcn.influx.service.CommonService;
import com.njcn.influx.service.HaronicRatioService;
import com.njcn.influx.service.PowerQualityService;
import com.njcn.influx.utils.InfluxDbUtils;
import com.njcn.system.api.CsStatisticalSetFeignClient;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.api.EpdFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.EleEpdPqd;
import lombok.RequiredArgsConstructor;
import org.influxdb.dto.QueryResult;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

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

/**
 * Description:
 * Date: 2023/5/18  14:39【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
@Service
@RequiredArgsConstructor
public class StableDataServiceImpl implements StableDataService {

    private final CsLineFeignClient csLineFeignClient;
    private final PowerQualityService powerQualityService;
    private final  HaronicRatioService harmonicRatioService;
    private final CsLedgerFeignClient csLedgerFeignClient;
    private final EpdFeignClient epdFeignClient;
    private final CommonService commonService;
    private final DecimalFormat df = new DecimalFormat("#0.0000");
    private final DicDataFeignClient dicDataFeignClient;
    private final InfluxDbUtils influxDbUtils;
    private final CsStatisticalSetFeignClient csStatisticalSetFeignClient;
    private final InfluxDbParamUtil influxDbParamUtil;
    private final EquipmentFeignClient equipmentFeignClient;
    private final String GRID_SIDE_DICT_CODE = "Grid_Side";
    private final String LOAD_SIDE_DICT_CODE = "Load_Side";
    private final IPqGovernPlanService pqGovernPlanService;


    @Override
    public List<ThdDataVO> queryThdData(String devId, String statisticalName) {
        List<ThdDataVO>  thdDataVOList = new ArrayList<>();
        List<CsLinePO> csLinePOList = csLineFeignClient.queryLineByDevId(devId).getData();
        Optional.ofNullable(csLinePOList).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR));
        List<String> collect = csLinePOList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        List<PowerQualityData> firstPowerQuality = powerQualityService.getFirstPowerQuality(collect, statisticalName);

        firstPowerQuality.forEach(temp->{
            ThdDataVO thdDataVO = new ThdDataVO();
            BeanUtils.copyProperties(temp,thdDataVO);
            thdDataVO.setStatisticalName(statisticalName);
            thdDataVO.setTime(temp.getTime());
            String position = csLinePOList.stream().filter(csLinePO -> Objects.equals(csLinePO.getLineId(), thdDataVO.getLineId())).collect(Collectors.toList()).get(0).getPosition();
            thdDataVO.setPosition(position);
            Double statisticalValue = 0.00;
            statisticalValue= (Double) ReflectUtils.getValue(temp, statisticalName);
            thdDataVO.setStatisticalData(statisticalValue);

            thdDataVOList.add(thdDataVO);

        });

        return thdDataVOList;
    }

    @Override
    public List<ThdDataVO> queryThdDataByTime(ThdDataQueryParm thdDataQueryParm) {
        List<ThdDataVO>  thdDataVOList = new ArrayList<>();
        List<CsLinePO> csLinePOList = csLineFeignClient.queryLineByDevId(thdDataQueryParm.getDevId()).getData();
        Optional.ofNullable(csLinePOList).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR));
        List<String> collect = csLinePOList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        List<PowerQualityData> firstPowerQuality = powerQualityService.getPowerQuality(collect, thdDataQueryParm.getStatisticalName(), thdDataQueryParm.getStartTime(), thdDataQueryParm.getEndTime());

        firstPowerQuality.forEach(temp->{
            ThdDataVO thdDataVO = new ThdDataVO();
            BeanUtils.copyProperties(temp,thdDataVO);
            thdDataVO.setStatisticalName(thdDataQueryParm.getStatisticalName());
            thdDataVO.setTime(temp.getTime());
            String position = csLinePOList.stream().filter(csLinePO -> Objects.equals(csLinePO.getLineId(), thdDataVO.getLineId())).collect(Collectors.toList()).get(0).getPosition();
            thdDataVO.setPosition(position);
            Double statisticalValue = 0.00;
            statisticalValue= (Double) ReflectUtils.getValue(temp, thdDataQueryParm.getStatisticalName());
            thdDataVO.setStatisticalData(statisticalValue);

            thdDataVOList.add(thdDataVO);

        });

        return thdDataVOList;
    }



    @Override
    public List<ThdDataVO> queryFisrtThdContent(String devId, String statisticalName) {
        List<ThdDataVO>  thdDataVOList = new ArrayList<>();
        List<CsLinePO> csLinePOList = csLineFeignClient.queryLineByDevId(devId).getData();
        Optional.ofNullable(csLinePOList).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR));
        List<String> collect = csLinePOList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        List<HarmonicRatioData> harmonicRatioList = harmonicRatioService.getFirstHaronicRatio(collect, statisticalName);
        harmonicRatioList.forEach(temp->{
            ThdDataVO thdDataVO = new ThdDataVO();
            BeanUtils.copyProperties(temp,thdDataVO);
            thdDataVO.setStatisticalName(statisticalName);
            thdDataVO.setTime(temp.getTime());
            String position = csLinePOList.stream().filter(csLinePO -> Objects.equals(csLinePO.getLineId(), thdDataVO.getLineId())).collect(Collectors.toList()).get(0).getPosition();
            thdDataVO.setPosition(position);
            Double statisticalValue = 0.00;
            statisticalValue= (Double) ReflectUtils.getValue(temp, statisticalName);
            thdDataVO.setStatisticalData(statisticalValue);

            thdDataVOList.add(thdDataVO);

        });

        return thdDataVOList;
    }

    @Override
    public List<ThdDataVO> queryThdContentByTime(ThdDataQueryParm thdDataQueryParm) {
        List<ThdDataVO>  thdDataVOList = new ArrayList<>();
        List<CsLinePO> csLinePOList = csLineFeignClient.queryLineByDevId(thdDataQueryParm.getDevId()).getData();
        Optional.ofNullable(csLinePOList).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR));
        List<String> collect = csLinePOList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        List<HarmonicRatioData> harmonicRatioList = harmonicRatioService.getHaronicRatio(collect, thdDataQueryParm.getStatisticalName(),thdDataQueryParm.getStartTime(), thdDataQueryParm.getEndTime());
        harmonicRatioList.forEach(temp->{
            ThdDataVO thdDataVO = new ThdDataVO();
            BeanUtils.copyProperties(temp,thdDataVO);
            thdDataVO.setStatisticalName(thdDataQueryParm.getStatisticalName());
            thdDataVO.setTime(temp.getTime());
            String position = csLinePOList.stream().filter(csLinePO -> Objects.equals(csLinePO.getLineId(), thdDataVO.getLineId())).collect(Collectors.toList()).get(0).getPosition();
            thdDataVO.setPosition(position);
            Double statisticalValue = 0.00;
            statisticalValue= (Double) ReflectUtils.getValue(temp, thdDataQueryParm.getStatisticalName());
            thdDataVO.setStatisticalData(statisticalValue);

            thdDataVOList.add(thdDataVO);

        });

        return thdDataVOList;
    }

    @Override
    public List<ThdDataVO> queryFisrtCommonStatistical(CommonStatisticalQueryParam commonStatisticalQueryParam) {
        List<String> collect = new ArrayList<>();
        List<CsLinePO> csLinePOList = new ArrayList<>();
        if(Objects.isNull(commonStatisticalQueryParam.getDevId())){
            if(!CollectionUtil.isEmpty(commonStatisticalQueryParam.getLineList())){
                collect =commonStatisticalQueryParam.getLineList();
                csLinePOList = csLineFeignClient.queryLineById(collect).getData();
            }else {
                throw new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR);
            }
        }else {
            csLinePOList = csLineFeignClient.queryLineByDevId(commonStatisticalQueryParam.getDevId()).getData();

        }
        List<CsEquipmentDeliveryDTO> data1 = equipmentFeignClient.queryDeviceById(Stream.of(commonStatisticalQueryParam.getDevId()).collect(Collectors.toList())).getData();
        String areaId =  dicDataFeignClient.getDicDataByCode(DicDataEnum.OUTPUT_SIDE.getCode()).getData().getId();

        Optional.ofNullable(csLinePOList).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR));
        List<CsLinePO> csLinePOList1 = csLinePOList.stream().filter(temp -> Objects.equals(areaId, temp.getPosition())).distinct().collect(Collectors.toList());


        EleEpdPqd data = epdFeignClient.selectById(commonStatisticalQueryParam.getStatisticalId()).getData();
        Optional.ofNullable(data).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.ELEEPDPQD_DATA_ERROR));
        String frequency ="";
        if(Objects.isNull(commonStatisticalQueryParam.getFrequency())){
            frequency ="";
        }else {
            frequency = "_"+commonStatisticalQueryParam.getFrequency();
        }
        String finalFrequency1 = frequency;
        List<CommonQueryParam> commonQueryParams = csLinePOList1.stream().map(temp -> {
            CommonQueryParam commonQueryParam = new CommonQueryParam();
            commonQueryParam.setLineId(temp.getLineId());
            commonQueryParam.setTableName(influxDbParamUtil.getTableNameByClassId(data.getClassId()));
            if (data.getName() == null || data.getName().isEmpty()) {
                commonQueryParam.setColumnName(data.getName()+ finalFrequency1);
            } else {
                commonQueryParam.setColumnName(data.getOtherName()+ finalFrequency1);
            }
            commonQueryParam.setPhasic(data.getPhase());
            commonQueryParam.setDataType(commonStatisticalQueryParam.getValueType().toUpperCase());
            commonQueryParam.setProcess(data1.get(0).getProcess()+"");
            commonQueryParam.setClDid(influxDbParamUtil.getClDidByLineId(temp.getLineId()));
            
            return commonQueryParam;
        }).collect(Collectors.toList());
        List<StatisticalDataDTO> deviceRtData = commonService.getDeviceRtData(commonQueryParams);
        List<CsLinePO> finalCsLinePOList = csLinePOList;
        String finalFrequency = frequency;
        List<ThdDataVO> collect1 = deviceRtData.stream().map(temp -> {
            ThdDataVO vo = new ThdDataVO();
            vo.setLineId(temp.getLineId());
            /*AB相映射A，BA相映射B，CA-》C*/

            vo.setPhase(phaseReflection(temp.getPhaseType()));
            String position = finalCsLinePOList.stream().filter(csLinePO -> Objects.equals(csLinePO.getLineId(), vo.getLineId())).collect(Collectors.toList()).get(0).getPosition();
            vo.setPosition(position);
            vo.setTime(temp.getTime());
            vo.setStatMethod(temp.getValueType());
            vo.setStatisticalData(Double.valueOf(df.format(temp.getValue())));
            vo.setStatisticalIndex(data.getId());
            vo.setStatisticalName(data.getName()+ finalFrequency +"("+data.getUnit()+")");
            vo.setAnotherName(data.getShowName());
            vo.setUnit(data.getUnit());

            return vo;
        }).collect(Collectors.toList());

        return collect1;
    }


    @Override
    public List<ThdDataVO> queryCommonStatisticalByTime(CommonStatisticalQueryParam commonStatisticalQueryParam) {
        List<ThdDataVO> result = new ArrayList<>();
        PqGovernPlan pqGovernPlan = pqGovernPlanService.getById(commonStatisticalQueryParam.getDevId());
        if(Objects.isNull(pqGovernPlan.getGovernBefore()) || Objects.isNull(pqGovernPlan.getGovernAfter())) {
            throw new BusinessException("治理前后监测点缺失，无法分析!");
        }
        CsLinePO loadSideLine = csLineFeignClient.getById(pqGovernPlan.getGovernBefore()).getData();
        CsLinePO gridSideLine = csLineFeignClient.getById(pqGovernPlan.getGovernAfter()).getData();
        List<CsEquipmentDeliveryDTO> devs = equipmentFeignClient.queryDeviceById(Arrays.asList(loadSideLine.getDeviceId(),gridSideLine.getDeviceId())).getData();
        Map<String,Integer> devMap = devs.stream().collect(Collectors.toMap(CsEquipmentDeliveryDTO::getId, CsEquipmentDeliveryDTO::getProcess));

        List<CsLinePO> csLinePOList1 = new ArrayList<>();
        csLinePOList1.add(gridSideLine);csLinePOList1.add(loadSideLine);
        List<EleEpdPqd> data = csStatisticalSetFeignClient.queryStatisticalSelect(Collections.singletonList(commonStatisticalQueryParam.getStatisticalId())).getData();
        if(CollectionUtil.isNotEmpty(data)){
            data.forEach(epdPqd->{
                String frequency = Optional.ofNullable(commonStatisticalQueryParam.getFrequency()).orElse("");
                if(StringUtils.isEmpty(commonStatisticalQueryParam.getFrequency())){
                    frequency ="";
                }else {
                    frequency = "_"+commonStatisticalQueryParam.getFrequency();
                }
                String finalFrequency1 = frequency;
                List<CommonQueryParam> commonQueryParams = csLinePOList1.stream().map(temp -> {
                    CommonQueryParam commonQueryParam = new CommonQueryParam();
                    commonQueryParam.setLineId(temp.getLineId());
                    commonQueryParam.setTableName(influxDbParamUtil.getTableNameByClassId(epdPqd.getClassId()));
                    if (epdPqd.getOtherName() == null || epdPqd.getOtherName().isEmpty()) {
                        commonQueryParam.setColumnName(epdPqd.getName()+ finalFrequency1);
                    } else {
                        commonQueryParam.setColumnName(epdPqd.getOtherName()+ finalFrequency1);
                    }
                    commonQueryParam.setPhasic(epdPqd.getPhase());
                    commonQueryParam.setStartTime(commonStatisticalQueryParam.getStartTime() + " 00:00:00");
                    commonQueryParam.setEndTime(commonStatisticalQueryParam.getEndTime() + " 23:59:59");
                    commonQueryParam.setDataType(commonStatisticalQueryParam.getValueType().toUpperCase());
                    commonQueryParam.setProcess(devMap.get(temp.getDeviceId())+"");
                    commonQueryParam.setClDid(influxDbParamUtil.getClDidByLineId(temp.getLineId()));

                    return commonQueryParam;
                }).collect(Collectors.toList());
                List<StatisticalDataDTO> deviceRtData = commonService.getDeviceRtDataByTime(commonQueryParams);
                if (CollectionUtil.isNotEmpty(deviceRtData)) {
                    Map<String, List<StatisticalDataDTO> > map = deviceRtData.stream().collect(Collectors.groupingBy(StatisticalDataDTO::getLineId));

                    List<StatisticalDataDTO> loadSideData = map.get(loadSideLine.getLineId());
                    if (CollectionUtil.isNotEmpty(loadSideData)) {
                        List<ThdDataVO> collect1 = loadSideData.stream().map(temp -> {
                            ThdDataVO vo = new ThdDataVO();
                            vo.setLineId(temp.getLineId());
                            vo.setPhase(temp.getPhaseType());
                            vo.setPosition(loadSideLine.getPosition());
                            vo.setTime(temp.getTime());
                            vo.setStatMethod(temp.getValueType());
                            vo.setStatisticalData(Double.valueOf(df.format(temp.getValue())));
                            vo.setStatisticalIndex(epdPqd.getId());
                            vo.setUnit(epdPqd.getUnit());
                            vo.setStatisticalName(epdPqd.getName());
                            vo.setAnotherName("治理前");
                            return vo;
                        }).collect(Collectors.toList());
                        result.addAll(collect1);
                    }

                    List<StatisticalDataDTO> gridSideData = map.get(gridSideLine.getLineId());
                    if (CollectionUtil.isNotEmpty(gridSideData)) {
                        List<ThdDataVO> collect2 = gridSideData.stream().map(temp -> {
                            ThdDataVO vo = new ThdDataVO();
                            vo.setLineId(temp.getLineId());
                            vo.setPhase(temp.getPhaseType());
                            vo.setPosition(gridSideLine.getPosition());
                            vo.setTime(temp.getTime());
                            vo.setStatMethod(temp.getValueType());
                            vo.setStatisticalData(Double.valueOf(df.format(temp.getValue())));
                            vo.setStatisticalIndex(epdPqd.getId());
                            vo.setUnit(epdPqd.getUnit());
                            vo.setStatisticalName(epdPqd.getName());
                            vo.setAnotherName("治理后");
                            return vo;
                        }).collect(Collectors.toList());
                        result.addAll(collect2);
                    }
                }
            });
        }
        return result;
    }

    private String phaseReflection(String phase){
        switch (phase) {
            case "AB":
                return "A";
            case "BC":
                return "B";
            case "CA":
                return "C";
            default:
                return phase;
        }
    }

    @Override
    public List<ThdDataVO> QuerySqlData(FrequencyStatisticalQueryParam frequencyStatisticalQueryParam) {
        List<String> collect = new ArrayList<>();
        List<CsLinePO> csLinePOList = new ArrayList<>();
        List<ThdDataVO> thdDataVOList = new ArrayList<>();
        if(Objects.isNull(frequencyStatisticalQueryParam.getDevId())){
            if(!CollectionUtil.isEmpty(frequencyStatisticalQueryParam.getLineList())){
                collect =frequencyStatisticalQueryParam.getLineList();
                csLinePOList = csLineFeignClient.queryLineById(collect).getData();
            }else {
                throw new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR);
            }
        }else {
            csLinePOList = csLineFeignClient.queryLineByDevId(frequencyStatisticalQueryParam.getDevId()).getData();

        }

        List<CsEquipmentDeliveryDTO> data1 = equipmentFeignClient.queryDeviceById(Stream.of(frequencyStatisticalQueryParam.getDevId()).collect(Collectors.toList())).getData();

        String areaId =  dicDataFeignClient.getDicDataByCode(DicDataEnum.OUTPUT_SIDE.getCode()).getData().getId();

        Optional.ofNullable(csLinePOList).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.LINE_DATA_ERROR));
        List<CsLinePO> collect1 = csLinePOList.stream().filter(temp -> Objects.equals(areaId, temp.getPosition())).collect(Collectors.toList());
        /*治理侧监测点*/
        CsLinePO csLinePO = collect1.get(0);

        EleEpdPqd data = epdFeignClient.selectById(frequencyStatisticalQueryParam.getStatisticalId()).getData();
        Optional.ofNullable(data).orElseThrow(()-> new BusinessException(AlgorithmResponseEnum.ELEEPDPQD_DATA_ERROR));

        StringBuilder stringBuilder1 = new StringBuilder();
        StringBuilder stringBuilder2 = new StringBuilder();

        for (int i = frequencyStatisticalQueryParam.getFrequencyStart(); i <=frequencyStatisticalQueryParam.getFrequencyEnd() ; i++) {
            if (i==frequencyStatisticalQueryParam.getFrequencyEnd()){
                stringBuilder1.append("last("+data.getName()).append("_"+i).append(") AS "+data.getName()).append("_"+i);
            } else {
                stringBuilder1.append("last("+data.getName()).append("_"+i).append(") AS "+data.getName()).append("_"+i).append(",");
            }
        }
        stringBuilder2.append ("line_id='").append (csLinePO.getLineId()).append("' and value_type = 'AVG' and process='"+data1.get(0).getProcess()+"' group by phasic_type ").append(InfluxDbSqlConstant.TZ);
        String sql1 = "select "+stringBuilder1+" from "+"apf_data"+" where "+stringBuilder2;

        QueryResult sqlData = influxDbUtils.query(sql1);
        List<QueryResult.Result> queryResults = sqlData.getResults();
        if (CollectionUtil.isNotEmpty(queryResults)) {
            for (QueryResult.Result result : queryResults) {
                if (CollectionUtil.isNotEmpty(result.getSeries())) {
                    List<QueryResult.Series> seriesList = result.getSeries();
                    if (CollectionUtil.isNotEmpty(seriesList)) {
                        //如果查询语句中存在group by，会存在多个series
                        for (QueryResult.Series series : seriesList) {
                            String key = data.getName();
                            for (int i = frequencyStatisticalQueryParam.getFrequencyStart(); i <=frequencyStatisticalQueryParam.getFrequencyEnd() ; i++) {
                                int i1 = i - frequencyStatisticalQueryParam.getFrequencyStart()+1;
                                Double value =  Double.parseDouble(series.getValues().get(0).get(i1).toString());
                                ThdDataVO thdDataVO = new ThdDataVO();
                                thdDataVO.setLineId(csLinePO.getLineId());
                                thdDataVO.setLineName(csLinePO.getName());
                                thdDataVO.setPhase(series.getTags().get("phasic_type"));
                                thdDataVO.setStatMethod("avg");
                                thdDataVO.setStatisticalData(Double.valueOf(df.format(value)));
                                thdDataVO.setStatisticalIndex(data.getId());
                                thdDataVO.setStatisticalName(data.getName()+ i +"("+data.getUnit()+")");
                                thdDataVO.setAnotherName(data.getShowName());
                                thdDataVO.setUnit(data.getUnit());
                                thdDataVOList.add(thdDataVO);

                            }
                        }
                    }
                }
            }
        }
        return thdDataVOList;
    }
}
