package com.njcn.product.advance.eventSource.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils;
import com.njcn.influx.imapper.DataHarmPowerPMapper;
import com.njcn.influx.imapper.DataHarmRateVMapper;
import com.njcn.influx.imapper.DataIMapper;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.influx.pojo.dto.HarmData;
import com.njcn.influx.pojo.dto.HarmHistoryDataDTO;
import com.njcn.influx.pojo.po.DataHarmPowerP;
import com.njcn.influx.pojo.po.DataHarmRateV;
import com.njcn.influx.pojo.po.DataI;
import com.njcn.influx.query.InfluxQueryWrapper;
import com.njcn.product.advance.eventSource.pojo.enums.AdvanceResponseEnum;
import com.njcn.product.advance.responsility.imapper.DataHarmP;
import com.njcn.product.advance.responsility.pojo.bo.UserDataExcel;
import com.njcn.product.advance.responsility.pojo.param.HistoryHarmParam;
import com.njcn.product.advance.eventSource.service.HistoryHarmonicService;
import com.njcn.product.advance.responsility.pojo.param.PHistoryHarmParam;
import com.njcn.product.terminal.mysqlTerminal.mapper.LineMapper;
import com.njcn.product.terminal.mysqlTerminal.mapper.OverlimitMapper;
import com.njcn.product.terminal.mysqlTerminal.pojo.dto.LineDevGetDTO;
import com.njcn.product.terminal.mysqlTerminal.pojo.po.Overlimit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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


/**
 * @Author: cdf
 * @CreateTime: 2025-09-08
 * @Description:
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class HistoryHarmonicServiceImpl implements HistoryHarmonicService {

    private final OverlimitMapper overlimitMapper;

    private final LineMapper lineMapper;

    private final DataIMapper dataIMapper;

    private final DataHarmRateVMapper dataHarmRateVMapper;

    private final DataHarmPowerPMapper dataHarmPowerPMapper;




    @Override
    public HarmHistoryDataDTO getHistoryHarmData(HistoryHarmParam historyHarmParam) {
        List<HarmData> historyData;
        float overLimit;
        Overlimit overlimit = overlimitMapper.selectById(historyHarmParam.getLineId());
        //判断是电流还是电压谐波
        if (historyHarmParam.getType() == 0) {
            historyData = getIHistoryData(historyHarmParam);
            overLimit = PubUtils.getValueByMethod(overlimit, "getIharm", historyHarmParam.getTime());
        } else {
            historyData = getVHistoryData(historyHarmParam);
            overLimit = PubUtils.getValueByMethod(overlimit, "getUharm", historyHarmParam.getTime());
        }
        return new HarmHistoryDataDTO(historyData, overLimit);
    }

    @Override
    public List<DataHarmPowerP> getHarmonicPData(PHistoryHarmParam historyHarmParam) {
        InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper(DataHarmPowerP.class);
        influxQueryWrapper
                .select(DataHarmPowerP::getP,DataHarmPowerP::getTime,DataHarmPowerP::getLineId)
                .eq(DataHarmPowerP::getPhaseType,InfluxDBTableConstant.PHASE_TYPE_T)
                .eq(DataHarmPowerP::getValueType,InfluxDBTableConstant.CP95)
                .regular(DataHarmPowerP::getLineId,historyHarmParam.getLineIds())
                .between(DataHarmPowerP::getTime,historyHarmParam.getSearchBeginTime().concat(InfluxDBTableConstant.START_TIME), historyHarmParam.getSearchEndTime().concat(InfluxDBTableConstant.END_TIME));
       List<DataHarmPowerP> dataHarmPowerPList = dataHarmPowerPMapper.selectByQueryWrapper(influxQueryWrapper);
       return dataHarmPowerPList;
    }


    /***
     * 获取指定次数 监测点的历史谐波电流数据
     * @author hongawen
     * @date 2023/7/19 10:03
     */
    private List<HarmData> getIHistoryData(HistoryHarmParam historyHarmParam) {
        LineDevGetDTO lineDetailData = lineMapper.getMonitorDetail(historyHarmParam.getLineId());
        List<HarmData> historyData;
        InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper(DataI.class, HarmData.class);
        influxQueryWrapper
                .select(DataI::getTime)
                .max("i_" + historyHarmParam.getTime(), "value")
                .between(DataI::getTime, historyHarmParam.getSearchBeginTime().concat(" 00:00:00"), historyHarmParam.getSearchEndTime().concat(" 23:59:59"))
                .eq(DataI::getLineId, historyHarmParam.getLineId())
                .or(DataI::getPhaseType, Stream.of(InfluxDBTableConstant.PHASE_TYPE_A, InfluxDBTableConstant.PHASE_TYPE_B, InfluxDBTableConstant.PHASE_TYPE_C).collect(Collectors.toList()))
                //以时间分组时，需要加上时间间隔，比如此处需要加上监测点的采样间隔
                .groupBy("time(" + lineDetailData.getInterval() + "m)")
                .timeAsc();
        String string = influxQueryWrapper.generateSql();
        historyData = dataIMapper.getIHistoryData(string);
        if (CollectionUtils.isEmpty(historyData)) {
            //如果数据为空，则提示给用户暂无数据
            throw new BusinessException(CommonResponseEnum.NO_DATA);
        }
        //最新两条数据的间隔与监测点查出的间隔做对比，返回一个合理的间隔
        historyData = historyData.stream().filter(Objects::nonNull).collect(Collectors.toList());
        int lineInterval = getInterval(lineDetailData.getInterval(), PubUtils.instantToDate(historyData.get(historyData.size() - 1).getTime()), PubUtils.instantToDate(historyData.get(historyData.size() - 2).getTime()));
        historyData = dealHistoryData(historyData, lineInterval);
        if (CollectionUtils.isEmpty(historyData)) {
            //如果数据为空，则提示给用户暂无数据
            throw new BusinessException(CommonResponseEnum.NO_DATA);
        }
        //根据时间天数，获取理论上多少次用采数据
        List<String> dateStr = PubUtils.getTimes(DateUtil.beginOfDay(DateUtil.parse(historyHarmParam.getSearchBeginTime())), DateUtil.endOfDay(DateUtil.parse(historyHarmParam.getSearchEndTime())));
        int dueTimes = dateStr.size() * 1440 / lineInterval;
        int realTimes = historyData.size();
        if (dueTimes != realTimes) {
            //期待值与实际值不等，则提示用户时间范围内谐波数据完整性不足
            throw new BusinessException(AdvanceResponseEnum.INSUFFICIENCY_OF_INTEGRITY);
        }
        return historyData.stream().sorted(Comparator.comparing(HarmData::getTime)).collect(Collectors.toList());
    }


    /**
     * 获取谐波电压的数据
     * <p>
     * 因历史谐波表data_harmrate_v
     */
    private List<HarmData> getVHistoryData(HistoryHarmParam historyHarmParam) {
        LineDevGetDTO lineDetailData = lineMapper.getMonitorDetail(historyHarmParam.getLineId());
        List<HarmData> historyData;
        InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper(DataHarmRateV.class, HarmData.class);
        influxQueryWrapper
                .select(DataHarmRateV::getTime)
                .max("v_" + historyHarmParam.getTime(), "value")
                .between(DataHarmRateV::getTime, historyHarmParam.getSearchBeginTime().concat(" 00:00:00"), historyHarmParam.getSearchEndTime().concat(" 23:59:59"))
                .eq(DataHarmRateV::getLineId, historyHarmParam.getLineId())
                .or(DataHarmRateV::getPhaseType, Stream.of(InfluxDBTableConstant.PHASE_TYPE_A, InfluxDBTableConstant.PHASE_TYPE_B, InfluxDBTableConstant.PHASE_TYPE_C).collect(Collectors.toList()))
                .groupBy("time(" + lineDetailData.getInterval() + "m)")
                .timeAsc();


        historyData = dataHarmRateVMapper.getHarmRateVHistoryData(influxQueryWrapper);
        if (CollectionUtils.isEmpty(historyData)) {
            //如果数据为空，则提示给用户暂无数据
            throw new BusinessException(CommonResponseEnum.NO_DATA);
        }
        historyData = historyData.stream().filter(Objects::nonNull).collect(Collectors.toList());
        int lineInterval = getInterval(lineDetailData.getInterval(), PubUtils.instantToDate(historyData.get(historyData.size() - 1).getTime()), PubUtils.instantToDate(historyData.get(historyData.size() - 2).getTime()));
        //最新两条数据的间隔与监测点查出的间隔做对比，返回一个合理的间隔
        historyData = dealHistoryData(historyData, lineInterval);
        if (CollectionUtils.isEmpty(historyData)) {
            //如果数据为空，则提示给用户暂无数据
            throw new BusinessException(CommonResponseEnum.NO_DATA);
        }
        //根据时间天数，获取理论上多少次用采数据
        List<String> dateStr = PubUtils.getTimes(DateUtil.beginOfDay(DateUtil.parse(historyHarmParam.getSearchBeginTime())), DateUtil.endOfDay(DateUtil.parse(historyHarmParam.getSearchEndTime())));
        int dueTimes = dateStr.size() * 1440 / lineInterval;
        int realTimes = historyData.size();
        if (dueTimes != realTimes) {
            //期待值与实际值不等，则提示用户时间范围内谐波数据完整性不足
            throw new BusinessException(AdvanceResponseEnum.INSUFFICIENCY_OF_INTEGRITY);
        }
        return historyData.stream().sorted(Comparator.comparing(HarmData::getTime)).collect(Collectors.toList());
    }


    /**
     * 获取合理的测量间隔
     */
    private int getInterval(int lineInterval, Date lastOne, Date lastTwo) {
        int interval = 0;
        Calendar one = Calendar.getInstance();
        one.setTime(lastOne);
        Calendar two = Calendar.getInstance();
        two.setTime(lastTwo);
        long oneTime = lastOne.getTime();
        long twoTime = lastTwo.getTime();
        long intvalTime = oneTime - twoTime;
        long databaseInterval = lineInterval * 60 * 1000;
        if (oneTime < twoTime || intvalTime >= databaseInterval) {
            interval = lineInterval;
        }
        if (intvalTime < databaseInterval) {
            interval = (int) (intvalTime / (1000 * 60));
        }
        return interval;
    }



    /**
     * 根据库中查询的数据，进行数据补齐操作
     *
     * @param beforeDeal 库中实际的历史谐波数据
     */
    private List<HarmData> dealHistoryData(List<HarmData> beforeDeal, int lineInterval) {
        List<HarmData> result = new ArrayList<>();
        try {
            if (CollectionUtils.isEmpty(beforeDeal)) {
                return result;
            } else {
                //先将查询数据按日进行收集
                Map<String/*yyyy-MM-dd的时间格式*/, Map<Date, HarmData>/*当前天的所有谐波数据*/> dayHistoryDatas = new HashMap<>();
                for (HarmData harmData : beforeDeal) {
                    Date time = PubUtils.instantToDate(harmData.getTime());
                    String date = DateUtil.format(time, DatePattern.NORM_DATE_PATTERN);
                    if (dayHistoryDatas.containsKey(date)) {
                        Map<Date, HarmData> harmDataMap = dayHistoryDatas.get(date);
                        harmDataMap.put(PubUtils.getSecondsAsZero(PubUtils.instantToDate(harmData.getTime())), harmData);
                        dayHistoryDatas.put(date, harmDataMap);
                    } else {
                        Map<Date, HarmData> harmDataMap = new HashMap<>();
                        harmDataMap.put(PubUtils.getSecondsAsZero(PubUtils.instantToDate(harmData.getTime())), harmData);
                        dayHistoryDatas.put(date, harmDataMap);
                    }
                }
                //将数据按日期处理后，开始进行完整性判断，满足完整性则进行补齐，否则返回空数据
                Set<String> days = dayHistoryDatas.keySet();
                for (String day : days) {
                    //获取出当天的历史谐波数据
                    Map<Date, HarmData> harmDataMap = dayHistoryDatas.get(day);
                    if (CollectionUtils.isEmpty(harmDataMap)) {
                        continue;
                    }
                    int dueTimes = 1440 / lineInterval;
                    int realTimes = harmDataMap.size();
                    double integrity = (double) realTimes / (double) dueTimes;
                    if (integrity < 0.9 || integrity >= 1.0) {
                        //完整性不足，则返回原数据
                        Set<Date> dates = harmDataMap.keySet();
                        for (Date time : dates) {
                            result.add(harmDataMap.get(time));
                        }
                    } else if (integrity < 1.0) {
                        //进行数据补齐,数据补齐需要根据监测点测量间隔,最好是MAP格式 map的key是yyyy-MM-dd HH:mm
                        List<HarmData> afterDeal = new ArrayList<>();
                        String timeTemp = day + " 00:00:00";
                        Date date = DateUtil.parse(timeTemp, DatePattern.NORM_DATETIME_PATTERN);
                        for (int i = 0; i < dueTimes; i++) {
                            Calendar calendar = Calendar.getInstance();
                            calendar.setTime(date);
                            calendar.add(Calendar.MINUTE, lineInterval * i);
                            HarmData temp = harmDataMap.get(calendar.getTime());
                            if (temp != null && temp.getValue() != null) {
                                afterDeal.add(temp);
                            } else {
                                //递归找到前面的值
                                Float preValue = getPreHarmValue(date, calendar.getTime(), harmDataMap, lineInterval);
                                //递归找到后面的值
                                Float appendValue = getAppendHarmValue(date, calendar.getTime(), harmDataMap, lineInterval);
                                HarmData harmData = new HarmData();
                                harmData.setTime(PubUtils.dateToInstant(calendar.getTime()));
                                //还需要判断前值和后值为空的情况
                                if (null == preValue && null == appendValue) {
                                    harmData.setValue(0.0f);
                                } else if (null == preValue) {
                                    harmData.setValue(appendValue);
                                } else if (null == appendValue) {
                                    harmData.setValue(preValue);
                                } else {
                                    harmData.setValue((preValue + appendValue) / 2);
                                }
                                afterDeal.add(harmData);
                            }
                        }
                        result.addAll(afterDeal);
                    }
                }
            }
        } catch (Exception e) {
            log.error("开始处理历史电压谐波数据失败，失败原因:{}", e.toString());
            throw new BusinessException(AdvanceResponseEnum.INSUFFICIENCY_OF_INTEGRITY);
        }
        return result;
    }

    /**
     * 递归找前值 谐波数据
     *
     * @param date       起始时间
     * @param time       当前事件
     * @param beforeDeal 处理前的数据
     */
    private Float getPreHarmValue(Date date, Date time, Map<Date, HarmData> beforeDeal, int interval) {
        Float result;
        if (date.getTime() >= time.getTime()) {
            return null;
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(time);
            interval = -interval;
            calendar.add(Calendar.MINUTE, interval);
            HarmData temp = beforeDeal.get(calendar.getTime());
            if (temp == null || temp.getValue() == null) {
                result = getPreHarmValue(date, calendar.getTime(), beforeDeal, Math.abs(interval));
            } else {
                result = temp.getValue();
            }
        }
        return result;
    }


    /**
     * 递归找后置 谐波数据
     *
     * @param date 起始时间
     * @param time 截止时间
     */
    private Float getAppendHarmValue(Date date, Date time, Map<Date, HarmData> beforeDeal, int interval) {
        Float result;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.MINUTE, -interval);
        if (calendar.getTimeInMillis() <= time.getTime()) {
            return null;
        } else {
            Calendar calendar1 = Calendar.getInstance();
            calendar1.setTime(time);
            calendar1.add(Calendar.MINUTE, interval);
            HarmData temp = beforeDeal.get(calendar1.getTime());
            if (temp == null || temp.getValue() == null) {
                result = getAppendHarmValue(date, calendar1.getTime(), beforeDeal, interval);
            } else {
                result = temp.getValue();
            }
        }
        return result;
    }

}
