package com.njcn.harmonic.service.influxdb.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.njcn.common.utils.HarmonicTimesUtil;
import com.njcn.dataProcess.param.LineCountEvaluateParam;
import com.njcn.dataProcess.pojo.dto.DataVDto;
import com.njcn.harmonic.service.influxdb.IDataV;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import com.njcn.influx.imapper.DataVMapper;
import com.njcn.influx.pojo.po.DataV;
import com.njcn.influx.query.InfluxQueryWrapper;
import com.njcn.redis.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wr
 * @description
 * @date 2026/7/1 10:49
 */
@Slf4j
@Service
public class InfluxdbDataVImpl   implements IDataV {

    private final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
    private static final Map<String, String> PHASE_MAPPING = new HashMap<String, String>() {{
        put("AB", "A");
        put("BC", "B");
        put("CA", "C");
        put("M", "T");
    }};
    @Resource
    private DataVMapper dataVMapper;
    @Resource
    private RedisUtil redisUtil;
    private static final Set<String> LINE_VOLTAGE_TYPES =
            Collections.unmodifiableSet(new HashSet<>(Arrays.asList("AB", "BC", "CA", "T")));
    private static final Set<String> PHASE_VOLTAGE_TYPES =
            Collections.unmodifiableSet(new HashSet<>(Arrays.asList("A", "B", "C", "T")));

    @Override
    public List<DataVDto> getRawData(LineCountEvaluateParam lineParam) {
        List<DataVDto> result = new ArrayList<>();
        List<DataV> list = getMinuteDataV(lineParam);
        if (CollectionUtil.isNotEmpty(list)) {
            list.forEach(item -> {
                DataVDto dto = new DataVDto();
                BeanUtils.copyProperties(item, dto);
                dto.setMinTime(DATE_TIME_FORMATTER.format(item.getTime()));
                result.add(dto);
            });
        }
        return result;
    }

    /**
     * 按监测点集合、时间条件获取dataV分钟数据
     * timeMap参数来判断是否进行数据处理 timeMap为空则不进行数据处理
     * 剔除异常数据,这里会有三种情况判断
     * 1.无异常数据，则直接返回集合；
     * 2.异常数据和无异常数据参杂，剔除异常数据，只计算正常数据；
     * 3.全是异常数据，则使用异常数据进行计算，但是日表中需要标记出来，此数据有异常
     */
    public List<DataV> getMinuteDataV(LineCountEvaluateParam lineParam) {
        List<DataV> result = new ArrayList<>();
        List<DataV> data = new ArrayList<>();
        //获取监测点、接线方式数据
        Type type = new TypeToken<Map<String, Integer>>(){}.getType();
        Map<String, Integer> map = new Gson().fromJson(
                String.valueOf(redisUtil.getObjectByKey("wlLineDetail")),
                type
        );
        InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper(DataV.class);
        influxQueryWrapper.samePrefixAndSuffix(InfluxDbSqlConstant.V, InfluxDbSqlConstant.V, HarmonicTimesUtil.harmonicTimesList(1, 50, 1));
        influxQueryWrapper.regular(DataV::getLineId, lineParam.getLineId())
                .select(DataV::getLineId)
                .select(DataV::getPhaseType)
                .select(DataV::getValueType)
                .select(DataV::getFreq)
                .select(DataV::getFreqDev)
                .select(DataV::getRms)
                .select(DataV::getRmsLvr)
                .select(DataV::getVNeg)
                .select(DataV::getVPos)
                .select(DataV::getVThd)
                .select(DataV::getVUnbalance)
                .select(DataV::getVZero)
                .select(DataV::getVlDev)
                .select(DataV::getVuDev)
                .select(DataV::getQualityFlag)
                .select(DataV::getAbnormalFlag)
                .between(DataV::getTime, lineParam.getStartTime(), lineParam.getEndTime())
                .eq(DataV::getQualityFlag, "0");
        if (CollUtil.isNotEmpty(lineParam.getPhasicType())) {
            influxQueryWrapper.regular(DataV::getPhaseType, lineParam.getPhasicType());
        }
        quality(result, influxQueryWrapper, lineParam);
        if (CollectionUtil.isNotEmpty(result)) {
            if (!Objects.isNull(map)) {
                //现根据监测点分组，然后根据接线方式排除多于数据，在修改相别
                Map<String, List<DataV>> lineMap = result.stream().collect(Collectors.groupingBy(DataV::getLineId));
                lineMap.forEach((k,v)->{
                    if (Objects.isNull(map.get(k))) {
                        return;
                    }
                    //这边需要特殊处理下，将线电压数据赋值
                    Map<String, DataV> lineVoltageIndex = v.stream()
                            .filter(d -> PHASE_MAPPING.containsKey(d.getPhaseType()))
                            .filter(d -> d.getRmsLvr() != null)
                            .collect(Collectors.toMap(
                                    d -> buildKey(d.getTime(), d.getValueType(), d.getPhaseType()),
                                    Function.identity(),
                                    (existing, replacement) -> existing
                            ));
                    v.stream()
                            .filter(d -> PHASE_VOLTAGE_TYPES.contains(d.getPhaseType()))
                            .forEach(phaseData -> {
                                // 根据当前相电压反查对应的线电压相别
                                String targetLinePhasic = getReverseLinePhasic(phaseData.getPhaseType());
                                if (targetLinePhasic == null) {
                                    return;
                                }
                                String key = buildKey(phaseData.getTime(), phaseData.getValueType(), targetLinePhasic);
                                DataV matchedLineData = lineVoltageIndex.get(key);
                                if (matchedLineData != null && matchedLineData.getRmsLvr() != null) {
                                    phaseData.setRmsLvr(matchedLineData.getRmsLvr());
                                }
                            });
                    Integer conType = map.get(k);
                    Set<String> validPhasicTypes = (conType != 0) ? LINE_VOLTAGE_TYPES : PHASE_VOLTAGE_TYPES;
                    List<DataV> result2 = v.stream().filter(item -> validPhasicTypes.contains(item.getPhaseType())).collect(Collectors.toList());
                    data.addAll(result2);
                });
            } else {
                data.addAll(result);
            }
            if (CollectionUtil.isNotEmpty(data)) {
                data.forEach(item -> {
                    String newType = PHASE_MAPPING.get(item.getPhaseType());
                    if (newType != null) {
                        item.setPhaseType(newType);
                    }
                });
            }
        }
        return data;
    }
    private void quality(List<DataV> result, InfluxQueryWrapper influxQueryWrapper, LineCountEvaluateParam lineParam) {
        List<DataV> dataList;
        List<DataV> list = dataVMapper.selectByQueryWrapper(influxQueryWrapper);
        if (CollUtil.isNotEmpty(list)) {
            //过滤掉暂态事件影响的数据 true过滤 false不过滤
            if (lineParam.getDataType()) {
                dataList = list.stream().filter(item -> Objects.isNull(item.getAbnormalFlag())).collect(Collectors.toList());
            } else {
                dataList = list;
            }
            Map<String, List<DataV>> lineMap = dataList.stream().collect(Collectors.groupingBy(DataV::getLineId));
            //有异常数据
            Map<String, List<String>> timeMap = lineParam.getAbnormalTime();
            if (CollectionUtil.isNotEmpty(timeMap)) {
                lineMap.forEach((k, v) -> {
                    List<String> timeList = timeMap.get(k);
                    //有异常数据,当前监测点自身的异常数据
                    if (CollectionUtil.isNotEmpty(timeList)) {
                        List<DataV> filterList = v.stream().filter(item -> !timeList.contains(DATE_TIME_FORMATTER.format(item.getTime()))).collect(Collectors.toList());
                        //1.过滤掉异常数据后还有正常数据，则用正常数据计算
                        if (CollectionUtil.isNotEmpty(filterList)) {
                            result.addAll(filterList);
                        }
                        //2.过滤掉异常数据后没有正常数据，则用所有异常数据计算，但是需要标记数据为异常的
                        else {
                            v.parallelStream().forEach(item -> item.setQualityFlag("1"));
                            result.addAll(v);
                        }
                    }
                    //没有异常数据，则使用原数据
                    else {
                        result.addAll(v);
                    }
                });
            }
            //没有异常数据，则使用原数据
            else {
                result.addAll(dataList);
            }
        }
    }

    private static String buildKey(Object time, Object valueType, Object phasicType) {
        return time + "|" + valueType + "|" + phasicType;
    }

    private static String getReverseLinePhasic(String phaseType) {
        if (phaseType == null) {
            return null;
        }
        switch (phaseType) {
            case "A":
                return "AB";
            case "B":
                return "BC";
            case "C":
                return "CA";
            default:
                return null;
        }
    }
}
