package com.njcn.csdevice.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.njcn.csdevice.service.IPqdDataSplitService;
import com.njcn.influx.pojo.po.*;
import com.njcn.influx.pojo.po.cs.PqdData;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.api.EpdFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.system.pojo.po.EleEpdPqd;
import com.njcn.system.pojo.vo.EleEpdPqdListVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * PqdData数据拆分服务实现
 *
 * @author system
 * @since 2026-05-22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PqdDataSplitServiceImpl implements IPqdDataSplitService {
    private final RedisUtil redisUtil;
    private final EpdFeignClient epdFeignClient;
    private final DicDataFeignClient dicDataFeignClient;
    @Override
    public Map<String, Object> splitPqdData(List<PqdData> pqdDataList) {
        //获取表映射关系
        Map<String,String> map1 = new Gson().fromJson(String.valueOf(redisUtil.getObjectByKey(AppRedisKey.ELE_EPD_PQD)), Map.class);
        //获取字段映射关系
        DictData pqd = dicDataFeignClient.getDicDataByCode(DicDataEnum.PQD.getCode()).getData();
        List<EleEpdPqdListVO> list = epdFeignClient.selectAll().getData();
        List<EleEpdPqd> epdList = list.stream().filter(item -> Objects.equals(item.getDataType(), pqd.getId()))
                .findFirst()
                .map(EleEpdPqdListVO::getEleEpdPqdVOS)
                .orElse(new ArrayList<>());
        // 处理 harmStart 和 harmEnd
        List<EleEpdPqd> resultList = epdList.stream()
                .flatMap(item -> {
                    if (item.getHarmStart() != null && item.getHarmEnd() != null) {
                        List<EleEpdPqd> expandedList = new ArrayList<>();
                        for (int i = item.getHarmStart(); i <= item.getHarmEnd(); i++) {
                            EleEpdPqd newItem = copyEleEpdPqd(item);
                            newItem.setName(item.getName() + "_" + i);
                            newItem.setOtherName(item.getOtherName() + "_" + i);
                            expandedList.add(newItem);
                        }
                        return expandedList.stream();
                    } else {
                        return Stream.of(item);
                    }
                })
                .collect(Collectors.toList());
        Map<String,List<EleEpdPqd>> map2 = resultList.stream().collect(Collectors.groupingBy(EleEpdPqd::getName,LinkedHashMap::new,Collectors.toList()));
        Map<String,Object> map3 = new HashMap<>();
        List<Object> list1 = new ArrayList<>();
        List<Object> list2 = new ArrayList<>();
        List<Object> list3 = new ArrayList<>();
        List<Object> list4 = new ArrayList<>();
        List<Object> list5 = new ArrayList<>();
        List<Object> list6 = new ArrayList<>();
        List<Object> list7 = new ArrayList<>();
        List<Object> list8 = new ArrayList<>();
        List<Object> list9 = new ArrayList<>();
        List<Object> list10 = new ArrayList<>();
        List<Object> list11 = new ArrayList<>();
        List<Object> list12 = new ArrayList<>();
        List<Object> list13 = new ArrayList<>();
        List<Object> list14 = new ArrayList<>();



        for (PqdData item : pqdDataList) {
            Map<String, Object> map = extractFieldValues(item);

            DataV dataV = new DataV();
            dataV.setTime(item.getTime());
            dataV.setLineId(item.getLineId());
            dataV.setPhaseType(item.getPhaseType());
            dataV.setValueType(item.getValueType());
            dataV.setClDid(item.getClDid());
            dataV.setProcess(item.getProcess());
            dataV.setQualityFlag("0");

            DataI dataI = new DataI();
            dataI.setTime(item.getTime());
            dataI.setLineId(item.getLineId());
            dataI.setPhaseType(item.getPhaseType());
            dataI.setValueType(item.getValueType());
            dataI.setClDid(item.getClDid());
            dataI.setProcess(item.getProcess());
            dataI.setQualityFlag("0");

            DataFlicker dataFlicker = new DataFlicker();
            dataFlicker.setTime(item.getTime());
            dataFlicker.setLineId(item.getLineId());
            dataFlicker.setPhaseType(item.getPhaseType());
            dataFlicker.setValueType(item.getValueType());
            dataFlicker.setClDid(item.getClDid());
            dataFlicker.setProcess(item.getProcess());
            dataFlicker.setQualityFlag("0");

            DataFluc dataFluc = new DataFluc();
            dataFluc.setTime(item.getTime());
            dataFluc.setLineId(item.getLineId());
            dataFluc.setPhaseType(item.getPhaseType());
            dataFluc.setValueType(item.getValueType());
            dataFluc.setClDid(item.getClDid());
            dataFluc.setProcess(item.getProcess());
            dataFluc.setQualityFlag("0");

            DataHarmPhasicI dataHarmPhasicI = new DataHarmPhasicI();
            dataHarmPhasicI.setTime(item.getTime());
            dataHarmPhasicI.setLineId(item.getLineId());
            dataHarmPhasicI.setPhaseType(item.getPhaseType());
            dataHarmPhasicI.setValueType(item.getValueType());
            dataHarmPhasicI.setClDid(item.getClDid());
            dataHarmPhasicI.setProcess(item.getProcess());
            dataHarmPhasicI.setQualityFlag("0");

            DataHarmPhasicV dataHarmPhasicV = new DataHarmPhasicV();
            dataHarmPhasicV.setTime(item.getTime());
            dataHarmPhasicV.setLineId(item.getLineId());
            dataHarmPhasicV.setPhaseType(item.getPhaseType());
            dataHarmPhasicV.setValueType(item.getValueType());
            dataHarmPhasicV.setClDid(item.getClDid());
            dataHarmPhasicV.setProcess(item.getProcess());
            dataHarmPhasicV.setQualityFlag("0");

            DataHarmPowerP dataHarmPowerP = new DataHarmPowerP();
            dataHarmPowerP.setTime(item.getTime());
            dataHarmPowerP.setLineId(item.getLineId());
            dataHarmPowerP.setPhaseType(item.getPhaseType());
            dataHarmPowerP.setValueType(item.getValueType());
            dataHarmPowerP.setClDid(item.getClDid());
            dataHarmPowerP.setProcess(item.getProcess());
            dataHarmPowerP.setQualityFlag("0");

            DataHarmPowerQ dataHarmPowerQ = new DataHarmPowerQ();
            dataHarmPowerQ.setTime(item.getTime());
            dataHarmPowerQ.setLineId(item.getLineId());
            dataHarmPowerQ.setPhaseType(item.getPhaseType());
            dataHarmPowerQ.setValueType(item.getValueType());
            dataHarmPowerQ.setClDid(item.getClDid());
            dataHarmPowerQ.setProcess(item.getProcess());
            dataHarmPowerQ.setQualityFlag("0");

            DataHarmPowerS dataHarmPowerS = new DataHarmPowerS();
            dataHarmPowerS.setTime(item.getTime());
            dataHarmPowerS.setLineId(item.getLineId());
            dataHarmPowerS.setPhaseType(item.getPhaseType());
            dataHarmPowerS.setValueType(item.getValueType());
            dataHarmPowerS.setClDid(item.getClDid());
            dataHarmPowerS.setProcess(item.getProcess());
            dataHarmPowerS.setQualityFlag("0");

            DataHarmRateV dataHarmRateV = new DataHarmRateV();
            dataHarmRateV.setTime(item.getTime());
            dataHarmRateV.setLineId(item.getLineId());
            dataHarmRateV.setPhaseType(item.getPhaseType());
            dataHarmRateV.setValueType(item.getValueType());
            dataHarmRateV.setClDid(item.getClDid());
            dataHarmRateV.setProcess(item.getProcess());
            dataHarmRateV.setQualityFlag("0");

            DataHarmRateI dataHarmRateI = new DataHarmRateI();
            dataHarmRateI.setTime(item.getTime());
            dataHarmRateI.setLineId(item.getLineId());
            dataHarmRateI.setPhaseType(item.getPhaseType());
            dataHarmRateI.setValueType(item.getValueType());
            dataHarmRateI.setClDid(item.getClDid());
            dataHarmRateI.setProcess(item.getProcess());
            dataHarmRateI.setQualityFlag("0");

            DataInHarmV dataInHarmV = new DataInHarmV();
            dataInHarmV.setTime(item.getTime());
            dataInHarmV.setLineId(item.getLineId());
            dataInHarmV.setPhaseType(item.getPhaseType());
            dataInHarmV.setValueType(item.getValueType());
            dataInHarmV.setClDid(item.getClDid());
            dataInHarmV.setProcess(item.getProcess());
            dataInHarmV.setQualityFlag("0");

            DataPlt dataPlt = new DataPlt();
            dataPlt.setTime(item.getTime());
            dataPlt.setLineId(item.getLineId());
            dataPlt.setPhaseType(item.getPhaseType());
            dataPlt.setValueType(item.getValueType());
            dataPlt.setClDid(item.getClDid());
            dataPlt.setProcess(item.getProcess());
            dataPlt.setQualityFlag("0");

            PqdData pqdData = new PqdData();
            pqdData.setTime(item.getTime());
            pqdData.setLineId(item.getLineId());
            pqdData.setPhaseType(item.getPhaseType());
            pqdData.setValueType(item.getValueType());
            pqdData.setClDid(item.getClDid());
            pqdData.setProcess(item.getProcess());
            pqdData.setQualityFlag("0");


            boolean hasDataV = false;
            boolean hasDataI = false;
            boolean hasData1 = false;
            boolean hasData2 = false;
            boolean hasData3 = false;
            boolean hasData4 = false;
            boolean hasData5 = false;
            boolean hasData6 = false;
            boolean hasData7 = false;
            boolean hasData8 = false;
            boolean hasData9 = false;
            boolean hasData10 = false;
            boolean hasData11 = false;
            boolean hasData12 = false;

            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String fieldName = entry.getKey();
                Object value = entry.getValue();
                String capitalizedFieldName = StringUtils.capitalize(fieldName);

                // 跳过公共字段和 null 值
                if (isCommonField(fieldName) || value == null) {
                    continue;
                }

                String table = map1.get(capitalizedFieldName);
                if (StrUtil.isBlank(table)) {
                    continue;
                }

                List<EleEpdPqd> epdPqdList = map2.get(capitalizedFieldName);
                if (CollectionUtils.isEmpty(epdPqdList)) {
                    continue;
                }

                String influxdbName2 = epdPqdList.get(0).getOtherName();
                if (StrUtil.isBlank(influxdbName2) || influxdbName2.equals(capitalizedFieldName)) {
                    influxdbName2 = capitalizedFieldName;
                }

                if (Objects.equals(table, "data_v")) {
                    setFieldValue(dataV, influxdbName2, value, true);
                    hasDataV = true;
                }
                if (Objects.equals(table, "data_i")) {
                    setFieldValue(dataI, influxdbName2, value, true);
                    hasDataI = true;
                }
                if (Objects.equals(table, "data_flicker")) {
                    setFieldValue(dataFlicker, influxdbName2, value, true);
                    hasData1 = true;
                }
                if (Objects.equals(table, "data_fluc")) {
                    setFieldValue(dataFluc, influxdbName2, value, true);
                    hasData2 = true;
                }
                if (Objects.equals(table, "data_harmphasic_i")) {
                    setFieldValue(dataHarmPhasicI, influxdbName2, value, true);
                    hasData3 = true;
                }
                if (Objects.equals(table, "data_harmphasic_v")) {
                    setFieldValue(dataHarmPhasicV, influxdbName2, value, true);
                    hasData4 = true;
                }
                if (Objects.equals(table, "data_harmpower_p")) {
                    setFieldValue(dataHarmPowerP, influxdbName2, value, true);
                    hasData5 = true;
                }
                if (Objects.equals(table, "data_harmpower_q")) {
                    setFieldValue(dataHarmPowerQ, influxdbName2, value, true);
                    hasData6 = true;
                }
                if (Objects.equals(table, "data_harmpower_s")) {
                    setFieldValue(dataHarmPowerS, influxdbName2, value, true);
                    hasData7 = true;
                }
                if (Objects.equals(table, "data_harmrate_v")) {
                    setFieldValue(dataHarmRateV, influxdbName2, value, true);
                    hasData8 = true;
                }
                if (Objects.equals(table, "data_harmrate_i")) {
                    setFieldValue(dataHarmRateI, influxdbName2, value, true);
                    hasData9 = true;
                }
                if (Objects.equals(table, "data_inharm_v")) {
                    setFieldValue(dataInHarmV, influxdbName2, value, true);
                    hasData10 = true;
                }
                if (Objects.equals(table, "data_plt")) {
                    setFieldValue(dataPlt, influxdbName2, value, true);
                    hasData11 = true;
                }
                if (Objects.equals(table, "pqd_data")) {
                    setFieldValue(pqdData, StringUtils.uncapitalize(influxdbName2), value, false);
                    hasData12 = true;
                }
            }

            if (hasDataV) {
                list1.add(dataV);
            }
            if (hasDataI) {
                list2.add(dataI);
            }
            if (hasData1) {
                list3.add(dataFlicker);
            }
            if (hasData2) {
                list4.add(dataFluc);
            }
            if (hasData3) {
                list5.add(dataHarmPhasicI);
            }
            if (hasData4) {
                list6.add(dataHarmPhasicV);
            }
            if (hasData5) {
                list7.add(dataHarmPowerP);
            }
            if (hasData6) {
                list8.add(dataHarmPowerQ);
            }
            if (hasData7) {
                list9.add(dataHarmPowerS);
            }
            if (hasData8) {
                list10.add(dataHarmRateV);
            }
            if (hasData9) {
                list11.add(dataHarmRateI);
            }
            if (hasData10) {
                list12.add(dataInHarmV);
            }
            if (hasData11) {
                list13.add(dataPlt);
            }
            if (hasData12) {
                list14.add(pqdData);
            }
        }

        map3.put("data_v", list1);
        map3.put("data_i", list2);
        map3.put("data_flicker", list3);
        map3.put("data_fluc", list4);
        map3.put("data_harmphasic_i", list5);
        map3.put("data_harmphasic_v", list6);
        map3.put("data_harmpower_p", list7);
        map3.put("data_harmpower_q", list8);
        map3.put("data_harmpower_s", list9);
        map3.put("data_harmrate_v", list10);
        map3.put("data_harmrate_i", list11);
        map3.put("data_inharm_v", list12);
        map3.put("data_plt", list13);
        map3.put("pqd_data", list14);
        return map3;
    }


    private Map<String, Object> extractFieldValues(PqdData pqdData) {
        Map<String, Object> fieldValues = new HashMap<>();
        Field[] fields = PqdData.class.getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(pqdData);
                if (value != null) {
                    fieldValues.put(field.getName(), value);
                } else {
                    fieldValues.put(field.getName(), 0.0d);
                }
            } catch (IllegalAccessException e) {
                log.warn("获取字段 {} 的值失败", field.getName(), e);
            }
        }
        return fieldValues;
    }


    private boolean isCommonField(String fieldName) {
        Set<String> commonFields = new HashSet<>(Arrays.asList(
                "time", "lineId", "phasicType", "valueType", "clDid",
                "process", "qualityFlag"
        ));
        return commonFields.contains(fieldName);
    }

    private void setFieldValue(Object obj, String fieldName, Object value, boolean isCamelCase) {
        try {
            String camelCaseFieldName = fieldName;
            if (isCamelCase) {
                camelCaseFieldName = toCamelCase(fieldName);
            }
            Field field = obj.getClass().getDeclaredField(camelCaseFieldName);
            field.setAccessible(true);
            if (value == null) {
                Class<?> fieldType = field.getType();
                if (fieldType == Double.class || fieldType == double.class) {
                    value = 0.0D;
                } else if (fieldType == Integer.class || fieldType == int.class) {
                    value = 0;
                } else if (fieldType == Float.class || fieldType == float.class) {
                    value = 0.0F;
                } else if (fieldType == Long.class || fieldType == long.class) {
                    value = 0L;
                } else {
                    return;
                }
            }
            field.set(obj, value);
        } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
            log.warn("设置字段 {} 的值失败", fieldName, e);
        }
    }


    public static String toCamelCase(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        StringBuilder result = new StringBuilder();
        boolean toUpper = false;

        for (char c : input.toCharArray()) {
            if (c == '_') {
                toUpper = true;
            } else {
                if (toUpper) {
                    result.append(Character.toUpperCase(c));
                    toUpper = false;
                } else {
                    result.append(c);
                }
            }
        }
        // 确保首字母小写，以匹配Java实体字段命名规范
        if (result.length() > 0 && Character.isUpperCase(result.charAt(0))) {
            result.setCharAt(0, Character.toLowerCase(result.charAt(0)));
        }
        return result.toString();
    }

    private EleEpdPqd copyEleEpdPqd(EleEpdPqd source) {
        if (source == null) {
            return null;
        }
        EleEpdPqd target = new EleEpdPqd();
        BeanUtils.copyProperties(source, target);
        return target;
    }
}
