package cn.cecep.talroad.service.impl.effective;


import cn.cecep.talroad.domain.PCodeStation;
import cn.cecep.talroad.domain.dto.PollutantCharacterAnalysisDto;
import cn.cecep.talroad.domain.effective.PCodeRegion;
import cn.cecep.talroad.mapper.PCodeStationMapper;
import cn.cecep.talroad.mapper.QEnvgasStationDayMapper;
import cn.cecep.talroad.mapper.effective.PCodeRegionMapper;
import cn.cecep.talroad.mapper.effective.QEnvgasWqDayMapper;
import cn.cecep.talroad.service.effective.PollutionCharacterAnalysisService;
import cn.cecep.talroad.util.PlxUtils;
import cn.cecep.talroad.util.effective.AirDataConverseUtil;
import cn.cecep.talroad.util.effective.DateUtil;
import cn.cecep.talroad.util.effective.FieldCache;
import cn.cecep.talroad.util.effective.NewDateUtil;
import cn.cecep.talroad.vo.effective.AirParmaVo;
import cn.cecep.talroad.vo.effective.AirQualityData;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ProjectName: szhpt-business
 * @Package: cn.cecep.talroad.service.impl
 * @ClassName: PollutionCharacterAnalysisServiceImpl
 * @Author: wyg
 * @Description:
 * @Date: 2023/6/13 15:14
 * @Version: 1.0
 */

@Service
public class PollutionCharacterAnalysisServiceImpl implements PollutionCharacterAnalysisService {

//    @Autowired
//    private EsSearchFeginService esSearchFeginService;
    @Autowired
    private QEnvgasWqDayMapper qEnvgasWqDayMapper;
    @Autowired
    private QEnvgasStationDayMapper qEnvgasStationDayMapper;
    @Autowired
    private FieldCache fieldCache;
    @Autowired
    private PCodeRegionMapper pCodeRegionMapper;
    @Autowired
    private PCodeStationMapper pCodeStationMapper;

    public static final SimpleDateFormat FOMRATDAY = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
    public static final String[][] HOUR_TEAM_ARR = {{"pm25", "pm10"}, {"pm25", "so2"}, {"pm25", "co"}, {"no2", "so2"}, {"o3", "nox"}};
    public static final String[][] DAY_TEAM_ARR = {{"pm25", "pm10"}, {"pm25", "so2"}, {"pm25", "co"}, {"no2", "so2"}};
    public static final String[] HOUR_TEAM_NAME_ARR = {"type1", "type2", "type3", "type4", "type5"};
    private static final BigDecimal PM25_PM10_RATIO_THIN = new BigDecimal("0.6");
    private static final BigDecimal PM25_PM10_RATIO_WEIGHT = new BigDecimal("0.4");
    private static final BigDecimal O3_QUALITY_NUMBER = new BigDecimal("48");
    private static final BigDecimal NOX_QUALITY_NUMBER = new BigDecimal("46");
    private static final BigDecimal STANDARD_DAQIYA = new BigDecimal("22.4");
    private static final BigDecimal NOX_CONTROL_AREA = new BigDecimal("5.7");


    @Override
    public List<Map<String, Object>> ratioOf(PollutantCharacterAnalysisDto analysisDto) {
        return calcRatio(getData(analysisDto), analysisDto);
    }

    @Override
    public double[][] plxValue(PollutantCharacterAnalysisDto analysisDto) {
        double[][] finalValueArray = new double[36][3];
        List<AirQualityData> data = getData(analysisDto);
        //获取六因子值list
        List<Double> pm25 = data.stream().map(e -> e.getPm25() == null ? 0.00 : e.getPm25().doubleValue()).collect(Collectors.toList());
        List<Double> pm10 = data.stream().map(e -> e.getPm10() == null ? 0.00 : e.getPm10().doubleValue()).collect(Collectors.toList());
        List<Double> so2 = data.stream().map(e -> e.getSo2() == null ? 0.00 : e.getSo2().doubleValue()).collect(Collectors.toList());
        List<Double> no2 = data.stream().map(e -> e.getNo2() == null ? 0.00 : e.getNo2().doubleValue()).collect(Collectors.toList());
        List<Double> co = data.stream().map(e -> e.getCo() == null ? 0.00 : e.getCo().doubleValue()).collect(Collectors.toList());
        List<Double> o3;
        if (analysisDto.getTimeType().equals(1)) {
            o3 = data.stream().map(e -> e.getO3() == null ? 0.00 : e.getO3().doubleValue()).collect(Collectors.toList());
        } else {
            o3 = data.stream().map(e -> e.getO38h() == null ? 0.00 : e.getO38h().doubleValue()).collect(Collectors.toList());
        }
        Map<String, List<Double>> readyCalcMap = new HashMap<>();
        readyCalcMap.put("pm25", pm25);
        readyCalcMap.put("pm10", pm10);
        readyCalcMap.put("so2", so2);
        readyCalcMap.put("no2", no2);
        readyCalcMap.put("co", co);
        readyCalcMap.put("o3", o3);
        String[] firstArray = {"o3", "co", "no2", "so2", "pm10", "pm25"};
        String[] secondArray = {"pm25", "pm10", "so2", "no2", "co", "o3"};
        //计算各个因子之间的关联性
        int finalIndex = 0;
        for (int i = 0; i < firstArray.length; i++) {
            List<Double> first = readyCalcMap.get(firstArray[i]).stream().filter(e -> e != null).collect(Collectors.toList());
            for (int j = 0; j < secondArray.length; j++) {
                List<Double> second = readyCalcMap.get(secondArray[j]).stream().filter(e -> e != null).collect(Collectors.toList());
                double result = PlxUtils.getPearsonCorrelationScore(first, second);
                if (!Double.isNaN(result)) {
                    finalValueArray[finalIndex] = new double[]{i, j, new BigDecimal(result).setScale(2, BigDecimal.ROUND_DOWN).doubleValue()};
                } else {
                    finalValueArray[finalIndex] = new double[]{i, j, result};
                }
                finalIndex++;
            }
        }
        return finalValueArray;
    }

    public List<AirQualityData> getData(PollutantCharacterAnalysisDto analysisDto) {
        Integer areaType = analysisDto.getAreaType();
        Integer timeType = analysisDto.getTimeType();
        AirParmaVo airParmaVo = new AirParmaVo();
        airParmaVo.setStartTime(analysisDto.getStartTime());
        airParmaVo.setEndTime(analysisDto.getEndTime());
        List<AirQualityData> qualityData = null;
        if (1==areaType) {
            //查询区域
            airParmaVo.setRegionCode(analysisDto.getSiteOrRegion());
            if (1==timeType) {
                  List<PCodeRegion> regionInfoList = pCodeRegionMapper.selectList(new QueryWrapper<PCodeRegion>().eq("region_code", analysisDto.getSiteOrRegion()));
//                qualityData = AirDataConverseUtil.convertEsAreaData(esSearchFeginService.areaData(airParmaVo).getData(), regionInfoList, airParmaVo);
            } else {
                qualityData = qEnvgasWqDayMapper.queryAreaDayData(airParmaVo);
            }
        } else {
            //查询站点
            airParmaVo.setStationId(analysisDto.getSiteOrRegion());
            if (1==timeType) {
                List<PCodeStation> stationInfoList = pCodeStationMapper.selectList(new QueryWrapper<PCodeStation>().eq("station_id", analysisDto.getSiteOrRegion()));
//                qualityData = AirDataConverseUtil.convertEsStationData(esSearchFeginService.stationData(airParmaVo).getData(), stationInfoList, airParmaVo);
            } else {
                qualityData = qEnvgasStationDayMapper.queryStationDaydata(airParmaVo);
            }
        }
        return qualityData;
    }

    /**
     * 计算各类型因子比值
     *
     * @param analysisDto 参数dto
     * @param data        区域/站点   小时/天数据
     * @return
     * @pram ratioType
     */
    List<Map<String, Object>> calcRatio(List<AirQualityData> data, PollutantCharacterAnalysisDto analysisDto) {
        List<Map<String, Object>> calcRatioTotalList = new ArrayList<>();
        //对数据按照时间倒序 排序
        if (1==analysisDto.getTimeType()) {
            data = data.stream().sorted(Comparator.comparing(e -> DateUtil.stringToDate(e.getMonitorTime(), DateUtil.HOUR_TIME_PATTERN))).collect(Collectors.toList());
        } else {
            if (data != null && data.size() > 0) {
                data = data.stream().filter(e -> StringUtils.isNotBlank(e.getMonitorTime())).collect(Collectors.toList());
                if (data != null && data.size() > 0) {
                    for (AirQualityData datum : data) {
                        datum.setMonitorTime(datum.getMonitorTime().concat(" 00:00:00"));
                    }
                }
            }
            data = data.stream().sorted(Comparator.comparing(e -> DateUtil.stringToDate(e.getMonitorTime(), DateUtil.HOUR_TIME_PATTERN))).collect(Collectors.toList());
        }
        //获取需要环比的因子列表
        List<Integer> ratioTypeList = analysisDto.getRatioType();
        for (Integer ratioType : ratioTypeList) {
            Map<String, Object> singleRatioType = new HashMap<>();
            List<String> timeList = new ArrayList<>();
            List<BigDecimal> ratioValueList = new ArrayList<>();
            List<BigDecimal> firstValueList = new ArrayList<>();
            List<BigDecimal> secondValueList = new ArrayList<>();
            List<String> thinTimeList = new ArrayList<>();
            List<String> weightTimeList = new ArrayList<>();
            //获取不同日期类型下污染因子字段名及名称
            String[][] teamArray;
            String[] teamNameArray;
            if (1==analysisDto.getTimeType()) {
                teamArray = HOUR_TEAM_ARR;
                teamNameArray = HOUR_TEAM_NAME_ARR;
            } else {
                teamArray = DAY_TEAM_ARR;
                teamNameArray = HOUR_TEAM_NAME_ARR;
            }
            List<BigDecimal> first = data.stream().map(e -> (BigDecimal) fieldCache.get(e, teamArray[ratioType - 1][0])).collect(Collectors.toList());
            List<BigDecimal> second = data.stream().map(e -> (BigDecimal) fieldCache.get(e, teamArray[ratioType - 1][1])).collect(Collectors.toList());
            if (first.size() == second.size()) {
                //将值进行对比
                for (int i = 0; i < first.size(); i++) {
                    BigDecimal firstDecimal = first.get(i);
                    BigDecimal secondDecimal = second.get(i);
                    BigDecimal result;
                    if (firstDecimal != null && firstDecimal.compareTo(BigDecimal.ZERO) != 0
                            && secondDecimal != null && secondDecimal.compareTo(BigDecimal.ZERO) != 0) {
                        if (ratioType.equals(5)) {
                            BigDecimal fd = firstDecimal.divide(O3_QUALITY_NUMBER, 1, BigDecimal.ROUND_HALF_EVEN).multiply(STANDARD_DAQIYA);
                            BigDecimal sd = secondDecimal.divide(NOX_QUALITY_NUMBER, 1, BigDecimal.ROUND_HALF_EVEN).multiply(STANDARD_DAQIYA);
                            result = fd.divide(sd, 1, BigDecimal.ROUND_HALF_EVEN);
                        } else {
                            result = firstDecimal.divide(secondDecimal, 1, BigDecimal.ROUND_HALF_EVEN);
                        }
                    } else {
                        result = null;
                    }
                    //需要进行特殊判断的比值组合 PM25/PM10   co/nox
                    if (ratioType.equals(1)) {
                        //细颗粒为主
                        if (result != null && result.compareTo(PM25_PM10_RATIO_THIN) == 1) {
                            thinTimeList.add(data.get(i).getMonitorTime());
                        }
                        //粗颗粒为主
                        if (result != null && result.compareTo(PM25_PM10_RATIO_WEIGHT) == -1) {
                            weightTimeList.add(data.get(i).getMonitorTime());
                        }
                    }
                    if (ratioType.equals(5)) {
                        //co比nox > 15
                        if (result != null && result.compareTo(NOX_CONTROL_AREA) == 1) {
                            weightTimeList.add(data.get(i).getMonitorTime());
                        }
                        if (result != null && result.compareTo(NOX_CONTROL_AREA) == -1) {
                            thinTimeList.add(data.get(i).getMonitorTime());
                        }
                    }
                    //比值
                    firstValueList.add(firstDecimal);
                    secondValueList.add(secondDecimal);
                    ratioValueList.add(result);
                    //时间
                    timeList.add(data.get(i).getMonitorTime());
                }
                singleRatioType.put("ratioData", ratioValueList);
                singleRatioType.put("firstData", firstValueList);
                singleRatioType.put("secondData", secondValueList);
                singleRatioType.put("times", timeList);
                // pm25/pm10
                if (ratioType.equals(1) || ratioType.equals(5)) {
                    if (thinTimeList != null && thinTimeList.size() > 0) {
                        thinTimeList = thinTimeList.stream().distinct().collect(Collectors.toList());
                        singleRatioType.put("thinTimeList", checkTimeisContinuation(thinTimeList, analysisDto.getTimeType()));
                    } else {
                        singleRatioType.put("thinTimeList", new ArrayList<>());
                    }
                    if (weightTimeList != null && weightTimeList.size() > 0) {
                        weightTimeList = weightTimeList.stream().distinct().collect(Collectors.toList());
                        singleRatioType.put("weightTimeList", checkTimeisContinuation(weightTimeList, analysisDto.getTimeType()));
                    } else {
                        singleRatioType.put("weightTimeList", new ArrayList<>());
                    }
                }
                Map<String, Object> finalMap = new HashMap<>();
                finalMap.put(teamNameArray[ratioType - 1], singleRatioType);
                calcRatioTotalList.add(finalMap);
            }
        }
        return calcRatioTotalList;
    }



    /**
     * 判断时间是否连续
     *
     * @param times 时间数组
     * @return
     */
    public List<List<String>> checkTimeisContinuation(List<String> times, Integer timeType) {
        List<List<String>> timeList = new ArrayList<>();
        if (times != null && times.size() > 0) {
            times.forEach(e -> {
                List<String> lxList1 = new ArrayList<>();
                lxList1.add(e);
                if (timeType == 1) {
                    lxList1.add(getNextHour(e));
                } else {
                    lxList1.add(getNextDay(e));
                }
                timeList.add(lxList1);
            });
        }
        return timeList;
    }

    /**
     * 获取下一个小时的时间字符串
     *
     * @return
     */
    String getNextHour(String time) {
        String pattern = "yyyy-MM-dd HH:00:00";
        Date date = DateUtil.stringToDate(time, pattern);
        Date lastDate = NewDateUtil.addDateHours(date, 1);
        return DateUtil.format(lastDate, pattern);
    }

    /**
     * 获取下一天的时间字符串
     *
     * @param time
     * @return
     */
    String getNextDay(String time) {
        String pattern = "yyyy-MM-dd 00:00:00";
        Date date = DateUtil.stringToDate(time, pattern);
        Date lastDate = NewDateUtil.addDateDays(date, 1);
        return DateUtil.format(lastDate, pattern);
    }

}

