package cn.cecep.talroad.service.impl;

import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.domain.*;
import cn.cecep.talroad.enums.TimeTypeEnum;
import cn.cecep.talroad.mapper.*;
import cn.cecep.talroad.service.ISEnvGasMonRealService;
import cn.cecep.talroad.util.CustomDateUtil;
import cn.cecep.talroad.vo.AmProblemFiVo;
import cn.cecep.talroad.vo.ChartVo;
import cn.cecep.talroad.vo.EChartsVO;
import cn.cecep.talroad.vo.SEnvGasMonRealVo;
import cn.cecep.talroad.vo.analysis.FactoryOutletStaticsVo;
import cn.cecep.talroad.vo.query.BMainEmissionSourceAirWaterSolidQuery;
import cn.cecep.talroad.vo.query.SEnvGasMonRealQuery;
import cn.cecep.talroad.vo.query.SEnvWaterMonRealQuery;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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


/**
 * 废气监测数据Service业务层处理
 *
 * @author szhpt
 * @date 2023-01-10*/
@Service
public class SEnvGasMonRealServiceImpl extends ServiceImpl<SEnvGasMonRealMapper,SEnvGasMonReal> implements ISEnvGasMonRealService
{
    @Autowired
    private SEnvGasMonRealMapper sEnvGasMonRealMapper;

    @Autowired
    private SEnvWaterMonRealMapper sEnvWaterMonRealMapper;

    @Autowired
    private STaskYieldTrendMapper sTaskYieldTrendMapper;

    @Autowired
    private PcYieldTrendMapper pcYieldTrendMapper;

    @Autowired
    private PcOutletMapper pcOutletMapper;

    @Autowired
    private HomePageMapServiceImpl homePageMapService;

    @Override
    public Map<String, Object> chart(BMainEmissionSourceAirWaterSolidQuery params) {
        Map<String, String> query = Maps.newHashMap();
        query.put("factoryId", params.getFactoryId());
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        Date date = new Date();
        Date toDate = null;
        String now = format.format(date);
        List<String> xsxisDatas = Lists.newArrayList();
        // 日、月、年
        switch (params.getDataType()){
            // 近一天
            case "日":
                c.setTime(date);
                c.add(Calendar.DATE, - 1);
                toDate = c.getTime();
                String begin = format.format(toDate);
                query.put("monitoringStartTime", begin);
                query.put("monitoringEndTime", now);
                query.put("dataType", TimeTypeEnum.HOUR.getCode());
                xsxisDatas.addAll(CustomDateUtil.getAllHours(toDate, date, CustomDateUtil.HOUR_PATTERN));
                break;
            // 近一月
            case "月":
                c.setTime(date);
                c.add(Calendar.MONTH, -1);
                toDate = c.getTime();
                String mon = format.format(toDate);
                query.put("monitoringStartTime", mon);
                query.put("monitoringEndTime", now);
                query.put("dataType", TimeTypeEnum.DAY.getCode());
                xsxisDatas.addAll(CustomDateUtil.getAllDays(toDate, date, CustomDateUtil.DATE_PATTERN));
                break;
            // 近一年
            case "年":
                c.setTime(new Date());
                c.add(Calendar.YEAR, -1);
                toDate = c.getTime();
                String year = format.format(toDate);
                query.put("monitoringStartTime", year);
                query.put("monitoringEndTime", now);
                query.put("dataType", params.getFacts().equals("行业") ? "M" : TimeTypeEnum.DAY.getCode());
                xsxisDatas.addAll(CustomDateUtil.getAllMonths(toDate, date, CustomDateUtil.DATE_PATTERN_MONTH));
                break;
        }
        Map<String, Object> res = Maps.newHashMap();
        ChartVo chartVo = new ChartVo();
        switch(params.getFacts()){
            case "废气":
                List<SEnvGasMonReal> sEnvGasMonReals = sEnvGasMonRealMapper.selectList(SEnvGasMonRealQuery.createLambdaQueryWrapper(new SEnvGasMonRealQuery(
                    query.get("factoryId"), query.get("dataType"), query.get("monitoringStartTime"), query.get("monitoringEndTime")
                )).orderByAsc("monitoring_time"));
                if(!CollectionUtils.isEmpty(sEnvGasMonReals)){
                    Map<String, List<SEnvGasMonReal>> mergeDataMaps = sEnvGasMonReals.stream().collect(Collectors.groupingBy(SEnvGasMonReal::getMonitoringTime));
                    List<SEnvGasMonReal> mergeDatas = Lists.newArrayList();
                    mergeDataMaps.forEach((month,data)->{
                        List<SEnvGasMonReal> timeData = new ArrayList<>(data.stream().collect(Collectors.toMap(SEnvGasMonReal::getMonitoringTime, a -> a, (o1, o2) -> {
                            o1.setSo2(strToBigDecimal(o1.getSo2()).add(strToBigDecimal(o2.getSo2())).toString());
                            o1.setNox(strToBigDecimal(o1.getNox()).add(strToBigDecimal(o2.getNox())).toString());
                            o1.setPm(strToBigDecimal(o1.getPm()).add(strToBigDecimal(o2.getPm())).toString());
                            o1.setVocs(strToBigDecimal(o1.getVocs()).add(strToBigDecimal(o2.getVocs())).toString());
                            return o1;
                        })).values());
                        mergeDatas.addAll(timeData);
                    });
                    Collections.sort(mergeDatas, new Comparator<SEnvGasMonReal>() {
                        @SneakyThrows
                        @Override
                        public int compare(SEnvGasMonReal o1, SEnvGasMonReal o2) {
                            Date o1Time = DateUtils.parseDate(o1.getMonitoringTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
                            Date o2Time = DateUtils.parseDate(o2.getMonitoringTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
                            if(o1Time.getTime() > o2Time.getTime()){
                                return 1;
                            } else if (o1Time.getTime() < o2Time.getTime()) {
                                return -1;
                            }
                            return 0;
                        }
                    });
                    if ("日".equals(params.getDataType())) {
                        mergeDatas.stream().forEach(item -> item.setMonitoringTime(item.getMonitoringTime().substring(0, 13)));
                    } else if ("月".equals(params.getDataType())) {
                        mergeDatas.stream().forEach(item -> item.setMonitoringTime(item.getMonitoringTime().substring(0, 10)));
                    } else if ("年".equals(params.getDataType())) {
                        mergeDatas.stream().forEach(item -> item.setMonitoringTime(item.getMonitoringTime().substring(0, 7)));
                    }
                    if("日".equals(params.getDataType()) || "月".equals(params.getDataType())){
                        chartVo.setXsxisData(mergeDatas.stream().map(SEnvGasMonReal::getMonitoringTime).distinct().collect(Collectors.toList()).toArray(new Object[0]));
                        chartVo.setLegendData(Arrays.stream(ChartVo.EnvGasMonRealPollutant.values()).distinct().map(ChartVo.EnvGasMonRealPollutant::getDesc).collect(Collectors.toList()).toArray(new Object[0]));
                        List<Map<Object, Object>> seriesData = Lists.newArrayList();
                        for (ChartVo.EnvGasMonRealPollutant value : ChartVo.EnvGasMonRealPollutant.values()) {
                            Map<Object, Object> map = Maps.newHashMap();
                            map.put("name", value.getDesc());
                            map.put("unit", "kg");
                            map.put("data", mergeDatas.stream().map(o -> BeanUtil.getProperty(o, value.getColumn())).collect(Collectors.toList()));
                            seriesData.add(map);
                        }
                        res.put("table", mergeDatas);
                        chartVo.setSeriesData(seriesData);
                    } else {
                        Map<String, List<SEnvGasMonReal>> mergeYearMonthDataMaps = mergeDatas.stream().collect(Collectors.groupingBy(SEnvGasMonReal::getMonitoringTime));
                        List<SEnvGasMonReal> mergeYearMonthDatas = Lists.newArrayList();
                        mergeYearMonthDataMaps.forEach((month,data)->{
                            List<SEnvGasMonReal> timeData = new ArrayList<>(data.stream().collect(Collectors.toMap(SEnvGasMonReal::getMonitoringTime, a -> a, (o1, o2) -> {
                                o1.setSo2(strToBigDecimal(o1.getSo2()).add(strToBigDecimal(o2.getSo2())).toString());
                                o1.setNox(strToBigDecimal(o1.getNox()).add(strToBigDecimal(o2.getNox())).toString());
                                o1.setPm(strToBigDecimal(o1.getPm()).add(strToBigDecimal(o2.getPm())).toString());
                                o1.setVocs(strToBigDecimal(o1.getVocs()).add(strToBigDecimal(o2.getVocs())).toString());
                                return o1;
                            })).values());
                            mergeYearMonthDatas.addAll(timeData);
                        });
                        Collections.sort(mergeYearMonthDatas, new Comparator<SEnvGasMonReal>() {
                            @SneakyThrows
                            @Override
                            public int compare(SEnvGasMonReal o1, SEnvGasMonReal o2) {
                                Date o1Time = DateUtils.parseDate(o1.getMonitoringTime(), DateUtils.YYYY_MM);
                                Date o2Time = DateUtils.parseDate(o2.getMonitoringTime(), DateUtils.YYYY_MM);
                                if(o1Time.getTime() > o2Time.getTime()){
                                    return 1;
                                } else if (o1Time.getTime() < o2Time.getTime()) {
                                    return -1;
                                }
                                return 0;
                            }
                        });
                        chartVo.setXsxisData(mergeYearMonthDatas.stream().map(SEnvGasMonReal::getMonitoringTime).distinct().collect(Collectors.toList()).toArray(new Object[0]));
                        chartVo.setLegendData(Arrays.stream(ChartVo.EnvGasMonRealPollutant.values()).distinct().map(ChartVo.EnvGasMonRealPollutant::getDesc).collect(Collectors.toList()).toArray(new Object[0]));
                        List<Map<Object, Object>> seriesData = Lists.newArrayList();
                        for (ChartVo.EnvGasMonRealPollutant value : ChartVo.EnvGasMonRealPollutant.values()) {
                            Map<Object, Object> map = Maps.newHashMap();
                            map.put("name", value.getDesc());
                            map.put("unit", "kg");
                            map.put("data", mergeYearMonthDatas.stream().map(o -> BeanUtil.getProperty(o, value.getColumn())).collect(Collectors.toList()));
                            seriesData.add(map);
                        }
                        res.put("table", mergeYearMonthDatas);
                        chartVo.setSeriesData(seriesData);
                    }
                } else {
                    chartVo.setSeriesData(Lists.newArrayList());
                    chartVo.setXsxisData(new Object[0]);
                    chartVo.setLegendData(new Object[0]);
                    res.put("table", Lists.newArrayList());
                }
                break;
            case "废水":
                List<SEnvWaterMonReal> sEnvWaterMonReals = sEnvWaterMonRealMapper.selectList(SEnvWaterMonRealQuery.createLambdaQueryWrapper(new SEnvWaterMonRealQuery(
                    query.get("factoryId"), query.get("dataType"), query.get("monitoringStartTime"), query.get("monitoringEndTime")
                )).orderByAsc("monitoring_time"));
                if(!CollectionUtils.isEmpty(sEnvWaterMonReals)){
                    // 近一年每月
                    Map<String, List<SEnvWaterMonReal>> mergeDataMaps = sEnvWaterMonReals.stream().collect(Collectors.groupingBy(SEnvWaterMonReal::getMonitoringTime));
                    List<SEnvWaterMonReal> mergeDatas = Lists.newArrayList();
                    mergeDataMaps.forEach((month,data)->{
                        List<SEnvWaterMonReal> monthData = new ArrayList<>(data.stream().collect(Collectors.toMap(SEnvWaterMonReal::getMonitoringTime, a -> a, (o1, o2) -> {
                            o1.setCodConcentration(strToBigDecimal(o1.getCodConcentration()).add(strToBigDecimal(o2.getCodConcentration())).toString());
                            o1.setPhosphorusConcentration(strToBigDecimal(o1.getPhosphorusConcentration()).add(strToBigDecimal(o2.getPhosphorusConcentration())).toString());
                            o1.setNitrogenConcentration(strToBigDecimal(o1.getNitrogenConcentration()).add(strToBigDecimal(o2.getNitrogenConcentration())).toString());
                            o1.setAmmoniaNitrogen(strToBigDecimal(o1.getAmmoniaNitrogen()).add(strToBigDecimal(o2.getAmmoniaNitrogen())).toString());
                            return o1;
                        })).values());
                        mergeDatas.addAll(monthData);
                    });
                    Collections.sort(mergeDatas, new Comparator<SEnvWaterMonReal>() {
                        @SneakyThrows
                        @Override
                        public int compare(SEnvWaterMonReal o1, SEnvWaterMonReal o2) {
                            Date o1Time = DateUtils.parseDate(o1.getMonitoringTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
                            Date o2Time = DateUtils.parseDate(o2.getMonitoringTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
                            if(o1Time.getTime() > o2Time.getTime()){
                                return 1;
                            } else if (o1Time.getTime() < o2Time.getTime()) {
                                return -1;
                            }
                            return 0;
                        }
                    });
                    if ("日".equals(params.getDataType())) {
                        sEnvWaterMonReals.stream().forEach(item -> item.setMonitoringTime(item.getMonitoringTime().substring(0, 13)));
                    } else if ("月".equals(params.getDataType())) {
                        sEnvWaterMonReals.stream().forEach(item -> item.setMonitoringTime(item.getMonitoringTime().substring(0, 10)));
                    } else if ("年".equals(params.getDataType())) {
                        sEnvWaterMonReals.stream().forEach(item -> item.setMonitoringTime(item.getMonitoringTime().substring(0, 7)));
                    }
                    if("日".equals(params.getDataType()) || "月".equals(params.getDataType())) {
                        chartVo.setXsxisData(mergeDatas.stream().map(SEnvWaterMonReal::getMonitoringTime).distinct().collect(Collectors.toList()).toArray(new Object[0]));
                        chartVo.setLegendData(Arrays.stream(ChartVo.EnvGasWaterRealPollutant.values()).distinct().map(ChartVo.EnvGasWaterRealPollutant::getDesc).collect(Collectors.toList()).toArray(new Object[0]));
                        List<Map<Object, Object>> seriesData = Lists.newArrayList();
                        for (ChartVo.EnvGasWaterRealPollutant value : ChartVo.EnvGasWaterRealPollutant.values()) {
                            Map<Object, Object> map = Maps.newHashMap();
                            map.put("name", value.getDesc());
                            map.put("unit", "kg");
                            map.put("data", sEnvWaterMonReals.stream().map(o -> BeanUtil.getProperty(o, value.getColumn())).collect(Collectors.toList()));
                            seriesData.add(map);
                        }
                        res.put("table", sEnvWaterMonReals);
                        chartVo.setSeriesData(seriesData);
                    } else {
                        // 近一年每月
                        Map<String, List<SEnvWaterMonReal>> mergeYearMonthDataMaps = sEnvWaterMonReals.stream().collect(Collectors.groupingBy(SEnvWaterMonReal::getMonitoringTime));
                        List<SEnvWaterMonReal> mergeYearMonthDatas = Lists.newArrayList();
                        mergeYearMonthDataMaps.forEach((month,data)->{
                            List<SEnvWaterMonReal> monthData = new ArrayList<>(data.stream().collect(Collectors.toMap(SEnvWaterMonReal::getMonitoringTime, a -> a, (o1, o2) -> {
                                o1.setCodConcentration(strToBigDecimal(o1.getCodConcentration()).add(strToBigDecimal(o2.getCodConcentration())).toString());
                                o1.setPhosphorusConcentration(strToBigDecimal(o1.getPhosphorusConcentration()).add(strToBigDecimal(o2.getPhosphorusConcentration())).toString());
                                o1.setNitrogenConcentration(strToBigDecimal(o1.getNitrogenConcentration()).add(strToBigDecimal(o2.getNitrogenConcentration())).toString());
                                o1.setAmmoniaNitrogen(strToBigDecimal(o1.getAmmoniaNitrogen()).add(strToBigDecimal(o2.getAmmoniaNitrogen())).toString());
                                return o1;
                            })).values());
                            mergeYearMonthDatas.addAll(monthData);
                        });
                        Collections.sort(mergeYearMonthDatas, new Comparator<SEnvWaterMonReal>() {
                            @SneakyThrows
                            @Override
                            public int compare(SEnvWaterMonReal o1, SEnvWaterMonReal o2) {
                                Date o1Time = DateUtils.parseDate(o1.getMonitoringTime(), DateUtils.YYYY_MM);
                                Date o2Time = DateUtils.parseDate(o2.getMonitoringTime(), DateUtils.YYYY_MM);
                                if(o1Time.getTime() > o2Time.getTime()){
                                    return 1;
                                } else if (o1Time.getTime() < o2Time.getTime()) {
                                    return -1;
                                }
                                return 0;
                            }
                        });
                        chartVo.setXsxisData(mergeYearMonthDatas.stream().map(SEnvWaterMonReal::getMonitoringTime).distinct().collect(Collectors.toList()).toArray(new Object[0]));
                        chartVo.setLegendData(Arrays.stream(ChartVo.EnvGasWaterRealPollutant.values()).distinct().map(ChartVo.EnvGasWaterRealPollutant::getDesc).collect(Collectors.toList()).toArray(new Object[0]));
                        List<Map<Object, Object>> seriesData = Lists.newArrayList();
                        for (ChartVo.EnvGasWaterRealPollutant value : ChartVo.EnvGasWaterRealPollutant.values()) {
                            Map<Object, Object> map = Maps.newHashMap();
                            map.put("name", value.getDesc());
                            map.put("unit", "kg");
                            map.put("data", mergeYearMonthDatas.stream().map(o -> BeanUtil.getProperty(o, value.getColumn())).collect(Collectors.toList()));
                            seriesData.add(map);
                        }
                        res.put("table", mergeYearMonthDatas);
                        chartVo.setSeriesData(seriesData);
                    }
                } else {
                    chartVo.setSeriesData(Lists.newArrayList());
                    chartVo.setXsxisData(new Object[0]);
                    chartVo.setLegendData(new Object[0]);
                    res.put("table", Lists.newArrayList());
                }
                break;
            case "行业":
                /**
                 * 焦化：装煤次数、推焦次数
                 * 转炉：炉数、公称容量、产量、出钢量
                 * 高炉：出铁量
                 * 水泥：生产端加料量(有)、水泥熟料产量（根据加料量折算出水泥熟料产量）
                 * 玻璃：退火窑实时车速、额定车速、产量
                 * 火电：机组负荷
                 * 垃圾焚烧：垃圾处理量(有)
                 */
                List<STaskYieldTrend> sTaskYieldTrends = sTaskYieldTrendMapper.selectList(new QueryWrapper<STaskYieldTrend>().eq("factory_id", query.get("factoryId")).eq("time_type", query.get("dataType")).between("data_time", DateUtils.parseDate(query.get("monitoringStartTime")), DateUtils.parseDate(query.get("monitoringEndTime"))).orderByAsc("data_time"));
                if(!CollectionUtils.isEmpty(sTaskYieldTrends)){
                    List<PcYieldTrend> pcYieldTrends = pcYieldTrendMapper.selectList(new QueryWrapper<PcYieldTrend>().eq("open", "1"));
                    Map<String, List<PcYieldTrend>> dictMaps = CollectionUtils.isEmpty(pcYieldTrends) ? Maps.newHashMap() : pcYieldTrends.stream().collect(Collectors.groupingBy(PcYieldTrend::getCode));
                    if ("日".equals(params.getDataType())) {
                        sTaskYieldTrends.stream().forEach(item -> item.setDataTime(DateUtils.parseFormatDate("yyyy-MM-dd HH",item.getDataTime())));
                    } else if ("月".equals(params.getDataType())) {
                        sTaskYieldTrends.stream().forEach(item -> item.setDataTime(DateUtils.parseFormatDate("yyyy-MM-dd",item.getDataTime())));
                    } else if ("年".equals(params.getDataType())) {
                        sTaskYieldTrends.stream().forEach(item -> item.setDataTime(DateUtils.parseFormatDate("yyyy-MM",item.getDataTime())));
                    }
                    chartVo.setXsxisData(sTaskYieldTrends.stream().map(STaskYieldTrend::getDataTime).distinct().collect(Collectors.toList()).toArray(new Object[0]));
                    chartVo.setLegendData(sTaskYieldTrends.stream().map(STaskYieldTrend::getDictCode).distinct().collect(Collectors.toList()).toArray(new Object[0]));
                    Map<String, STaskYieldTrend> dbDataMap = sTaskYieldTrends.stream().collect(Collectors.toMap(o -> o.getDeviceId() +o.getDictCode() + o.getDataTime(), o -> o));
                    List<Map<Object, Object>> seriesData = Lists.newArrayList();
                    for (int i = 0; i < chartVo.getLegendData().length; i++) {
                        Object legendDatum = chartVo.getLegendData()[i];
                        Map<Object, Object> map = Maps.newHashMap();
                        map.put("name", dictMaps.containsKey(legendDatum) ? dictMaps.get(legendDatum).get(0).getSmall() : legendDatum);
                        map.put("unit", dictMaps.containsKey(legendDatum) ? dictMaps.get(legendDatum).get(0).getUnit() : "--");
                        List<Object> data = Lists.newArrayList();
                        for (Object xsxisDatum : chartVo.getXsxisData()) {
                            data.add(dbDataMap.containsKey(legendDatum.toString() + xsxisDatum.toString()) ? dbDataMap.get(legendDatum.toString() + xsxisDatum.toString()).getNumber() : "");
                        }
                        chartVo.getLegendData()[i] = dictMaps.containsKey(legendDatum) ? dictMaps.get(legendDatum).get(0).getSmall() : legendDatum;
                        map.put("data", data);
                        seriesData.add(map);
                    }
                    chartVo.setSeriesData(seriesData);
                } else {
                    chartVo.setSeriesData(Lists.newArrayList());
                    chartVo.setXsxisData(new Object[0]);
                    chartVo.setLegendData(new Object[0]);
                    res.put("table", Lists.newArrayList());
                }
                break;
        }
        // 无数据默认补全x轴
        if(chartVo.getXsxisData().length == 0){
            chartVo.setXsxisData(xsxisDatas.stream().toArray());
        }
        // 数据缺失, 补全x轴及对应数据
        if(chartVo.getXsxisData().length != xsxisDatas.size()){
            CustomDateUtil.packEcharts(chartVo, xsxisDatas);
        }
        res.put("chart", chartVo);
        return res;
    }

    private BigDecimal strToBigDecimal(String str){
        if(StringUtil.isEmpty(str)){
            return BigDecimal.ZERO;
        } else {
            return new BigDecimal(StringUtil.trim(str));
        }
    }

    /**
     * 查询废气监测数据列表
     *
     * @param sEnvGasMonReal 废气监测数据
     * @return 废气监测数据
     */
    @Override
    public List<SEnvGasMonRealVo> selectSEnvGasMonRealList(SEnvGasMonRealQuery sEnvGasMonReal)
    {
        String format;
        switch (sEnvGasMonReal.getDataType()) {
            default:
                format = "yyyy-MM-dd HH:mm:ss";
                break;
            case "D":
                // 天
                format = "yyyy-MM-dd";
                break;
            case "H":
                // 小时
                format = "yyyy-MM-dd HH";
                break;
            case "M":
                // 分钟
                format = "yyyy-MM-dd HH:mm";
                break;
        }

        DateTime monitoringStartTime = DateUtil.parse(sEnvGasMonReal.getMonitoringStartTime(), format);
        DateTime monitoringEndTime = DateUtil.parse(sEnvGasMonReal.getMonitoringEndTime(), format);
        sEnvGasMonReal.setMonitoringStartTime(monitoringStartTime.toString());
        sEnvGasMonReal.setMonitoringEndTime(monitoringEndTime.toString());


        return sEnvGasMonRealMapper.selectSEnvGasMonRealList(null, sEnvGasMonReal, new QueryWrapper<SEnvGasMonReal>().orderByDesc("monitoring_time"," pf.factory_name,polet.outlet_code,po.monitoring_point_name"));
    }

    @Override
    public IPage<SEnvGasMonRealVo> selectSEnvGasMonRealPage(SEnvGasMonRealQuery sEnvGasMonReal) {
        Page<SEnvGasMonRealVo> page = new Page<>(sEnvGasMonReal.getPageNum(), sEnvGasMonReal.getPageSize());

        String format;
        switch (sEnvGasMonReal.getDataType()) {
            default:
                format = "yyyy-MM-dd HH:mm:ss";
                break;
            case "D":
                // 天
                format = "yyyy-MM-dd";
                break;
            case "H":
                // 小时
                format = "yyyy-MM-dd HH";
                break;
            case "M":
                // 分钟
                format = "yyyy-MM-dd HH:mm";
                break;
        }


        DateTime monitoringStartTime = DateUtil.parse(sEnvGasMonReal.getMonitoringStartTime(), format);
        DateTime monitoringEndTime = DateUtil.parse(sEnvGasMonReal.getMonitoringEndTime(), format);
        sEnvGasMonReal.setMonitoringStartTime(monitoringStartTime.toString());
        sEnvGasMonReal.setMonitoringEndTime(monitoringEndTime.toString());

        List<SEnvGasMonRealVo> sEnvGasMonRealVos = sEnvGasMonRealMapper.selectSEnvGasMonRealList(page, sEnvGasMonReal, new QueryWrapper<SEnvGasMonReal>().orderByDesc("monitoring_time"," pf.factory_name,polet.outlet_code,po.monitoring_point_name"));
        for (SEnvGasMonRealVo gasMonRealVo : sEnvGasMonRealVos) {
            // 拼接监测物标记
            gasMonRealVo.setSo2(joinFlag(gasMonRealVo.getSo2(), gasMonRealVo.getSo2Flag()));
            gasMonRealVo.setNox(joinFlag(gasMonRealVo.getNox(), gasMonRealVo.getNoxFlag()));
            gasMonRealVo.setNo(joinFlag(gasMonRealVo.getNo(), gasMonRealVo.getNoFlag()));
            gasMonRealVo.setNo2(joinFlag(gasMonRealVo.getNo2(), gasMonRealVo.getNo2Flag()));
            gasMonRealVo.setSmokeDust(joinFlag(gasMonRealVo.getSmokeDust(), gasMonRealVo.getSmokeDustFlag()));
            gasMonRealVo.setPm(joinFlag(gasMonRealVo.getPm(), gasMonRealVo.getPmFlag()));
            gasMonRealVo.setVocs(joinFlag(gasMonRealVo.getVocs(), gasMonRealVo.getVocsFlag()));
            gasMonRealVo.setO3(joinFlag(gasMonRealVo.getO3(), gasMonRealVo.getO3Flag()));
            gasMonRealVo.setOxygen(joinFlag(gasMonRealVo.getOxygen(), gasMonRealVo.getOxygenFlag()));
            gasMonRealVo.setSmokeDustTem(joinFlag(gasMonRealVo.getSmokeDustTem(), gasMonRealVo.getSmokeDustTemFlag()));
            gasMonRealVo.setSmokeDustPressure(joinFlag(gasMonRealVo.getSmokeDustPressure(), gasMonRealVo.getSmokeDustPressureFlag()));
            gasMonRealVo.setSmokeDustFlowVelocity(joinFlag(gasMonRealVo.getSmokeDustFlowVelocity(), gasMonRealVo.getSmokeDustFlowVelocityFlag()));
            gasMonRealVo.setSmokeDustHumidity(joinFlag(gasMonRealVo.getSmokeDustHumidity(), gasMonRealVo.getSmokeDustHumidityFlag()));
        }
        page.setRecords(sEnvGasMonRealVos);
        return page;
    }

    private String joinFlag(String value, String flag) {
        SEnvGasMonReal.ParamFlagEnum paramFlagEnum = SEnvGasMonReal.ParamFlagEnum.getByEnumName(flag);
        if (value == null && paramFlagEnum == null) {
            return null;
        }
        if (value == null) {
            value = "";
        }
        if (paramFlagEnum == null) {
            flag = "";
        } else {
            flag = "（" + paramFlagEnum.label + "）";
        }
        return value + flag;
    }

    /**
     * 废气有组织在线监测所有污染物
     */
    public enum PollutantEnum {
        so2("SO₂实测", "so2", "mg/m³", "A21026", "so2Flag"),
        so2Convert("SO₂折算", "so2Convert", "mg/m³", null, "so2Flag"),
        so2Emission("SO₂排放量", "so2Emission", "kg", null, "so2Flag"),

        nox("NOₓ实测", "nox", "mg/m³", "A21002", "noxFlag"),
        noxConvert("NOₓ折算", "noxConvert", "mg/m³", null, "noxFlag"),
        noxEmission("NOₓ排放量", "noxEmission", "kg", null, "noxFlag"),

        pm("颗粒物实测", "pm", "mg/m³", "A99911", "pmFlag"),
        pmConvert("颗粒物折算", "pmConvert", "mg/m³", null, "pmFlag"),
        pmEmission("颗粒物排放量", "pmEmission", "kg", null, "pmFlag"),

        vocs("VOCs实测", "vocs", "mg/m³", "A99907", "vocsFlag"),
        vocsConvert("VOCs折算", "vocsConvert", "mg/m³", null, "vocsFlag"),
        vocsEmission("VOCs排放量", "vocsEmission", "kg", null, "vocsFlag"),

        o3("氧气含量", "o3", "%", null, "o3Flag"),

        oxygen("废气流量", "oxygen", "m³/s", null, "oxygenFlag"),
        oxygenEmission("废气排放量", "oxygenEmission", "m³", null, "oxygenFlag"),

        smokeDust("烟尘", "smokeDust", "mg/m³", "A34013", "smokeDustFlag"),
        smokeDustConvert("烟尘折算", "smokeDustConvert", "mg/m³", null, "smokeDustFlag"),
        smokeDustEmission("烟尘排放量", "smokeDustEmission", "kg", null, "smokeDustFlag"),
        smokeDustTem("烟气温度", "smokeDustTem", "℃", null, "smokeDustTemFlag"),
        smokeDustPressure("烟气压力", "smokeDustPressure", "kPa", null, "smokeDustPressureFlag"),
        smokeDustFlowVelocity("烟气流速", "smokeDustFlowVelocity", "m/s", null, "smokeDustFlowVelocityFlag"),
        smokeDustHumidity("烟气湿度", "smokeDustHumidity", "%", null, "smokeDustHumidityFlag"),

        no("NO", "no", "mg/m³", "A21003", "noFlag"),
        noConvert("NO折算", "noConvert", "mg/m³", null, "noFlag"),
        noEmission("NO排放量", "noEmission", "kg", null, "noFlag"),

        no2("NO₂", "no2", "mg/m³", "A21004", "no2Flag"),
        no2Convert("NO₂折算", "no2Convert", "mg/m³", null, "no2Flag"),
        no2Emission("NO₂排放量", "no2Emission", "kg", null, "no2Flag"),
        ;

        public final String label; // 名称
        public final String prop; // 取值属性名
        public final String unit; // 单位
        public final String code; // 编码
        public final String flag; // 标记字段对应属性名

        PollutantEnum(String label, String prop, String unit, String code, String flag) {
            this.label = label;
            this.prop = prop;
            this.unit = unit;
            this.code = code;
            this.flag = flag;
        }

        public String getLabel() {
            return label;
        }

        public String getProp() {
            return prop;
        }

        public String getUnit() {
            return unit;
        }

        public String getCode() {
            return code;
        }

        public String getFlag() {
            return flag;
        }

        public static PollutantEnum getByProp(String prop) {
            for (PollutantEnum value : values()) {
                if (value.prop.equals(prop)) {
                    return value;
                }
            }
            return null;
        }
        public static PollutantEnum getByCode(String code) {
            for (PollutantEnum value : values()) {
                if (value.code != null && value.code.equals(code)) {
                    return value;
                }
            }
            return null;
        }
    }

    @Override
    public EChartsVO getCharData(SEnvGasMonRealQuery query) {
        // 结束日期格式补全，解决查询出的数据不包含结束日期的情况
        if (StringUtils.isNotEmpty(query.getMonitoringEndTime())) {
            Date date = DateUtils.parseDate(query.getMonitoringEndTime());
            query.setMonitoringEndTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", date));
        }
//        List<SEnvGasMonReal> sEnvGasMonReals = sEnvGasMonRealMapper.selectList(SEnvGasMonRealQuery.createLambdaQueryWrapper(query).orderByAsc("monitoring_time"));

        // x轴数据
        List<String> xdata = DateUtils.getRangeTimes(query.getDataType(), query.getMonitoringStartTime(), query.getMonitoringEndTime());

        List<SEnvGasMonReal> sEnvGasMonReals = sEnvGasMonRealMapper.selectSEnvGasMonRealListEchart(query);

        // 以日期为key,转为map 日期格式要保证与x轴格式一样
        Map<String, SEnvGasMonReal> gasMonRealMap = sEnvGasMonReals.stream().collect(Collectors.toMap(o -> {
            Date date = DateUtils.parseDate(o.getMonitoringTime());
            if (TimeTypeEnum.MONTH.getCode().equals(o.getDataType())) {
                return DateUtils.parseDateToStr("yyyy-MM-dd HH:mm", date);
            } else if (TimeTypeEnum.HOUR.getCode().equals(o.getDataType())) {
                return DateUtils.parseDateToStr("yyyy-MM-dd HH", date);
            } else {
                return DateUtils.parseDateToStr("yyyy-MM-dd", date);
            }
        }, o -> o,
                // TODO 数据问题导致存在key相同的，暂取第一条
                (o1, o2) -> o1));

        /*
            将查询到的监测数据转为曲线图要求的格式
         */
        List<EChartsVO.SeriesObj> series = new ArrayList<>();

        // 若query.getPollutantVos()不为null，则只展示指定的监测参数。（若指定的参数集合是空的，则返回空数据）
        if (query.getPollutantVos() != null) {
            // 去除掉prop属性为空的，并且通过map去重
            LinkedHashMap<String, AmProblemFiVo.PollutantVo> pollutantVoLinkedHashMap = query.getPollutantVos().stream()
                    .filter(o -> o.getProp() != null)
                    .collect(Collectors.toMap(o -> o.getProp(), o -> o,
                            // 保留第一个
                            (o1, o2) -> o1,
                            // 保持顺序不变
                            LinkedHashMap::new));
            query.setPollutantVos(new ArrayList<>(pollutantVoLinkedHashMap.values()));

            for (AmProblemFiVo.PollutantVo pollutantVo : query.getPollutantVos()) {
                PollutantEnum pollutantEnum = PollutantEnum.getByProp(pollutantVo.getProp());
                if (pollutantEnum == null) { // 无效的污染物，忽略
                    continue;
                }
                EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                ser.setName(pollutantEnum.label);
                ser.setUnit(pollutantEnum.unit);
                ser.setProp(pollutantEnum.prop);

                // 填充曲线图系列值。遍历x轴数据，保证x轴与系列数据一一对应
                List<Object> values = xdata.stream().map(o -> {
                    SEnvGasMonReal monReal = gasMonRealMap.get(o);
                    if (monReal == null) {
                        return null;
                    }
                    return BeanUtil.getProperty(monReal, ser.getProp());
                }).collect(Collectors.toList());
                ser.setValues(values);

                ser.setMarkLine(pollutantVo.getMarkLine());
                ser.setMarkArea(pollutantVo.getMarkArea());

                series.add(ser);

                List<EChartsVO.SeriesObj> limitSeries = getLimitSeriesObj(pollutantVo, pollutantEnum, xdata);
                if (limitSeries != null) {
                    // 由于当前遍历的监测参数存在上下限系列，设置系列类型为“problem”，前端会通过该属性特殊渲染
                    ser.setSeriesType("problem");
                    series.addAll(limitSeries);
                }

                List<EChartsVO.SeriesObj> flagSeriesObj = getFlagSeriesObj(pollutantVo, xdata, gasMonRealMap, pollutantEnum);
                if (flagSeriesObj != null) {
                    series.addAll(flagSeriesObj);
                }
            }
        } else { // 未指定监测参数，默认展示所有的
            for (PollutantEnum pollutantEnum : PollutantEnum.values()) {

                // 颗粒物与烟尘重复，此处排除颗粒物相关参数
                if (pollutantEnum.equals(PollutantEnum.pm) || pollutantEnum.equals(PollutantEnum.pmConvert) || pollutantEnum.equals(PollutantEnum.pmEmission)) {
                    continue;
                }

                // 排除no
                if (pollutantEnum.equals(PollutantEnum.no) || pollutantEnum.equals(PollutantEnum.noConvert) || pollutantEnum.equals(PollutantEnum.noEmission)) {
                    continue;
                }

                // 排除no2
                if (pollutantEnum.equals(PollutantEnum.no2) || pollutantEnum.equals(PollutantEnum.no2Convert) || pollutantEnum.equals(PollutantEnum.no2Emission)) {
                    continue;
                }

                EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                ser.setName(pollutantEnum.label);
                ser.setUnit(pollutantEnum.unit);
                ser.setProp(pollutantEnum.prop);

                // 遍历x轴数据，保证x轴与系列数据一一对应
                List<Object> values = xdata.stream().map(o -> {
                    SEnvGasMonReal monReal = gasMonRealMap.get(o);
                    if (monReal == null) {
                        return null;
                    }
                    return BeanUtil.getProperty(monReal, ser.getProp());
                }).collect(Collectors.toList());
                ser.setValues(values);
                series.add(ser);
            }
        }
        EChartsVO chartsVO = new EChartsVO();
        chartsVO.setXData(xdata);
        chartsVO.setSeries(series);
        return chartsVO;
    }

    /**
     * 若监测物是问题参数，需要生成状态标记相关系列
     */
    private List<EChartsVO.SeriesObj> getFlagSeriesObj(
            AmProblemFiVo.PollutantVo pollutantVo,
            List<String> xdata,
            Map<String, SEnvGasMonReal> gasMonRealMap,
            PollutantEnum pollutantEnum
    ) {
        if (pollutantVo.getProblemParam() == null || !pollutantVo.getProblemParam()) {
            return null;
        }
        Map<String, EChartsVO.SeriesObj> dataFlagSerMap = new HashMap<>();
        Map<String, EChartsVO.SeriesObj> paramFlagSerMap = new HashMap<>();

        // 计算x轴时间范围内有多少种dataFlag标记和有多少参数标记，并创建对应的系列对象
        for (String time : xdata) {
            SEnvGasMonReal real = gasMonRealMap.get(time);
            if (real == null) {
                continue;
            }
            SEnvGasMonReal.DataFlagEnum dataFlagEnum = SEnvGasMonReal.DataFlagEnum.getByEnumName(real.getDataFlag());

            // 若参数标记与dataFlag标记同时存在，优先取dataFlag标记
            if (dataFlagEnum != null) {
                if (!dataFlagSerMap.containsKey(dataFlagEnum.name())) {
                    EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                    ser.setName(dataFlagEnum.label + "（标记）");
                    ser.setProp(dataFlagEnum.name());
                    ser.setValues(new ArrayList<>());
                    dataFlagSerMap.put(dataFlagEnum.name(), ser);
                }
            } else {
                // 获取参数标记
                String propflag = BeanUtil.getProperty(real, pollutantEnum.flag);
                SEnvGasMonReal.ParamFlagEnum paramFlagEnum = SEnvGasMonReal.ParamFlagEnum.getByEnumName(propflag);

                if (paramFlagEnum != null && paramFlagEnum.show) {
                    if (!paramFlagSerMap.containsKey(paramFlagEnum.name())) {
                        EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                        ser.setName(paramFlagEnum.label + "（标记）");
                        ser.setProp(paramFlagEnum.name());
                        ser.setValues(new ArrayList<>());
                        paramFlagSerMap.put(paramFlagEnum.name(), ser);
                    }
                }
            }
        }

        // 所有的状态标记系列值保持一样
        final String Flag_Value = "1";

        // 填充系列值
        if (dataFlagSerMap.isEmpty() && paramFlagSerMap.isEmpty()) {
            return null;
        }

        // 遍历x轴，保证系列值与x轴一一对应
        for (int i = 0; i < xdata.size(); i++) {
            String time = xdata.get(i);

            // 默认所有系列填充null值
            for (EChartsVO.SeriesObj ser : dataFlagSerMap.values()) {
                ser.getValues().add(null);
            }
            for (EChartsVO.SeriesObj ser : paramFlagSerMap.values()) {
                ser.getValues().add(null);
            }

            SEnvGasMonReal real = gasMonRealMap.get(time);
            if (real == null) {
                continue;
            }
            SEnvGasMonReal.DataFlagEnum dataFlagEnum = SEnvGasMonReal.DataFlagEnum.getByEnumName(real.getDataFlag());

            if (dataFlagEnum != null) {
                dataFlagSerMap.get(dataFlagEnum.name()).getValues().set(i, Flag_Value);
            } else {
                // 获取参数标记
                String propflag = BeanUtil.getProperty(real, pollutantEnum.flag);
                SEnvGasMonReal.ParamFlagEnum paramFlagEnum = SEnvGasMonReal.ParamFlagEnum.getByEnumName(propflag);

                if (paramFlagEnum != null && paramFlagEnum.show) {
                    paramFlagSerMap.get(paramFlagEnum.name()).getValues().set(i, Flag_Value);
                }
            }
        }
        List<EChartsVO.SeriesObj> serList = new ArrayList<>();
        serList.addAll(new ArrayList<>(dataFlagSerMap.values()));
        serList.addAll(new ArrayList<>(paramFlagSerMap.values()));
        return serList;
    }

    /**
     * 若监测物指定了上下限，还需要生成上下限的曲线图
     */
    private List<EChartsVO.SeriesObj> getLimitSeriesObj(AmProblemFiVo.PollutantVo pollutantVo, PollutantEnum pollutantEnum, List<String> xdata) {
        if (pollutantVo.getPollutantLimitMap() == null) {
            return null;
        }
        EChartsVO.SeriesObj lowerLimit = new EChartsVO.SeriesObj();
        lowerLimit.setName(pollutantEnum.label + "下限");
        lowerLimit.setUnit(pollutantEnum.unit);
        lowerLimit.setProp("lowerLimit");
        lowerLimit.setSeriesType("lowerLimit");

        EChartsVO.SeriesObj upperLimit = new EChartsVO.SeriesObj();
        upperLimit.setName(pollutantEnum.label + "上限");
        upperLimit.setUnit(pollutantEnum.unit);
        upperLimit.setProp("upperLimit");
        upperLimit.setSeriesType("upperLimit");

        List<EChartsVO.SeriesObj> seriesObjs = Arrays.asList(lowerLimit, upperLimit);

        for (EChartsVO.SeriesObj seriesObj : seriesObjs) {
            // 填充曲线图系列值。遍历x轴数据，保证x轴与系列数据一一对应
            List<Object> values2 = xdata.stream().map(o -> {
                AmProblemFiVo.PollutantLimitVo pollutantLimitVo = pollutantVo.getPollutantLimitMap().get(o);
                if (pollutantLimitVo == null) {
                    return null;
                }
                return BeanUtil.getProperty(pollutantLimitVo, seriesObj.getProp());
            }).collect(Collectors.toList());
            seriesObj.setValues(values2);
        }
        return seriesObjs;
    }

    @Override
    public List<EChartsVO> getCharDataList(SEnvGasMonRealQuery query) {
        List<PcOutlet> children = pcOutletMapper.selectList(new QueryWrapper<PcOutlet>()
                .eq("parent_outlet_id", query.getOutletId())
                .eq("pollutant_type", "4")
        );

        return children.stream().map(child -> {
            query.setOutletId(child.getId());
            EChartsVO vo = getCharData(query);
            vo.setName(child.getMonitoringPointName());
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public Map<String, Object> chartNew(BMainEmissionSourceAirWaterSolidQuery query) {
        // 接口适配关系对应map
        Map<String, String> selectCorrespondenceMap = MapBuilder.<String, String>create()
                .put("废气", "1")
                .put("废水", "2")
                .put("行业", "3")
                .build();
        final String selectType = selectCorrespondenceMap.getOrDefault(query.getFacts(), "");
        Map<String, String> dateCorrespondenceMap = MapBuilder.<String, String>create()
                .put("年", "Y")
                .put("月", "M")
                .put("日", "D")
                .build();
        final String datatype = dateCorrespondenceMap.getOrDefault(query.getDataType(), "D");

        EChartsVO eChartsVO = null;
        if (StringUtils.isNotEmpty(selectType)) {
            eChartsVO = homePageMapService.emissionTrends(query.getFactoryId(), selectType, datatype, null, null);
        }

        if (Objects.isNull(eChartsVO)) {
            eChartsVO = new EChartsVO();
        }

        List<EChartsVO.SeriesObj> series = eChartsVO.getSeries();

        Map<String, Object> chartData = MapBuilder.<String, Object>create()
                .put("legendData", eChartsVO.getLegendData())
                .put("xsxisData", eChartsVO.getXData())
                .put("yaxisData", null)
                .put("seriesData", series.stream()
                                            .map(x -> MapBuilder.<String, Object>create()
                                                    .put("name", x.getName())
                                                    .put("unit", x.getUnit())
                                                    .put("data", x.getValues())
                                                    .build())
                                            .collect(Collectors.toList()))
                .build();
        return MapBuilder.<String, Object>create()
                .put("chart", chartData)
                .put("table", Lists.newArrayList())
                .build();
    }

    @Override
    public List<SEnvGasMonReal> selectLastHourData(String pollutantOutletType,Date lastHour) {
        return sEnvGasMonRealMapper.selectLastHourData(pollutantOutletType,lastHour);
    }


    @Override
    public List<FactoryOutletStaticsVo> selectLastDayData(DateTime queryBeginTime, DateTime queryEndTime) {
        return sEnvGasMonRealMapper.selectLastDayData(queryBeginTime,queryEndTime);
    }

}
