package cn.cecep.talroad.service.impl;

import cn.cecep.talroad.common.core.exception.ServiceException;
import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.domain.*;
import cn.cecep.talroad.domain.analysis.SRaRealTimeAnalysisCo;
import cn.cecep.talroad.enums.TimeTypeEnum;
import cn.cecep.talroad.mapper.*;
import cn.cecep.talroad.mapper.analysis.SRaRealTimeAnalysisCoMapper;
import cn.cecep.talroad.service.*;
import cn.cecep.talroad.util.CustomDateUtil;
import cn.cecep.talroad.vo.AmVideoDevFiVo;
import cn.cecep.talroad.vo.ChartVo;
import cn.cecep.talroad.vo.EChartsVO;
import cn.cecep.talroad.vo.MapPointVo;
import cn.cecep.talroad.vo.query.AmVideoDevFiQuery;
import cn.cecep.talroad.vo.query.SEnvGasMonRealQuery;
import cn.cecep.talroad.vo.query.SEnvGasRealQuery;
import cn.cecep.talroad.vo.query.SEnvWaterMonRealQuery;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: weizhuang
 * @Date:2023/2/16 15:39
 * @Version 1.0
 */
@Service
public class MonitoringMapServiceImpl implements IMonitoringMapService {

    @Autowired
    private MAmDoorMonitorAccountFiMapper mAmDoorMonitorAccountFiMapper;

    @Autowired
    private PcFactoryAccessControlMapper pcFactoryAccessControlMapper;

    @Autowired
    private IAmVideoDevFiService amVideoDevFiService;

    @Autowired
    private BasDeviceSiteMapper basDeviceSiteMapper;

    @Autowired
    private PcOutletMapper pcOutletMapper;

    @Autowired
    private BasDeviceMapper basDeviceMapper;

    @Autowired
    private MonElecRealMapper monElecRealMapper;

    @Autowired
    private PcFactoryPollutantMapper pcFactoryPollutantMapper;

    @Autowired
    private PcPollutantMapper pcPollutantMapper;

    @Autowired
    private ISEnvGasRealService sEnvGasRealService;

    @Autowired
    private ISEnvGasMonRealService envGasMonRealService;

    @Autowired
    private PcControlRequirementsMapper pcControlRequirementsMapper;

    @Autowired
    private ISEnvWaterMonRealService envWaterMonRealService;

    @Autowired
    private IBasDeviceService basDeviceService;

    @Autowired
    private PcIndustryMapper pcIndustryMapper;

    @Autowired
    private IotDeviceTypeMapper iotDeviceTypeMapper;

    @Autowired
    private BasDeviceSalAnalysisMapper basDeviceSalAnalysisMapper;


    @Autowired
    private SRaRealTimeAnalysisCoMapper sRaRealTimeAnalysisCoMapper;
    @Autowired
    private AmProblemFiMapper amProblemFiMapper;

    @Override
    public Map<String, Object> pullAccessControlPop(String factoryId, String accessControlCode) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("factoryId", factoryId);
        params.put("accessControlCode", accessControlCode);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        Date date = new Date();
        String now = format.format(date);
        // 近七天
        c.setTime(date);
        c.add(Calendar.DATE, - 7);
        Date d = c.getTime();
        String begin = format.format(d);
        params.put("startTime", begin);
        params.put("endTime", now);
        List<Map<String, Object>> pieChart = mAmDoorMonitorAccountFiMapper.selectByMaps(params);
        Map<String, Object> res = Maps.newHashMap();
        res.put("pieChart", CollectionUtils.isEmpty(pieChart) ? Lists.newArrayList() : pieChart);
        List<MAmDoorMonitorAccountFi> records = mAmDoorMonitorAccountFiMapper.selectLists(params);
        ChartVo chartVo = new ChartVo();
        if(!CollectionUtils.isEmpty(records)){
            records.stream().forEach(item -> item.setEntryTime(item.getEntryTime().substring(0, 13)));
            chartVo.setLegendData(new Object[]{"出厂","进厂"});
            chartVo.setXsxisData(records.stream().map(MAmDoorMonitorAccountFi::getEntryTime).distinct().collect(Collectors.toList()).toArray(new Object[0]));
            // 0-出厂, 1-进厂
            Map<String, List<MAmDoorMonitorAccountFi>> outRecords = CollectionUtils.isEmpty(records.stream().filter(item->item.getEntryType().equals("0")).collect(Collectors.toList())) ? Maps.newHashMap() : records.stream().filter(item->item.getEntryType().equals("0")).collect(Collectors.toList()).stream().collect(Collectors.groupingBy(MAmDoorMonitorAccountFi::getEntryTime));
            Map<String, List<MAmDoorMonitorAccountFi>> inRecords = CollectionUtils.isEmpty(records.stream().filter(item->item.getEntryType().equals("1")).collect(Collectors.toList())) ? Maps.newHashMap() : records.stream().filter(item->item.getEntryType().equals("1")).collect(Collectors.toList()).stream().collect(Collectors.groupingBy(MAmDoorMonitorAccountFi::getEntryTime));
            List<Map<Object, Object>> seriesData = Lists.newArrayList();
            if(!CollectionUtils.isEmpty(outRecords)){
                Map<Object, Object> map = Maps.newHashMap();
                map.put("name", "出厂");
                Object[] outData = new Object[chartVo.getXsxisData().length];
                for (int i = 0; i < chartVo.getXsxisData().length; i++) {
                    if(outRecords.containsKey(chartVo.getXsxisData()[i])){
                        outData[i] = outRecords.get(chartVo.getXsxisData()[i]).size();
                    } else {
                        outData[i] = null;
                    }
                }
                map.put("data", outData);
                seriesData.add(map);
            }
            if(!CollectionUtils.isEmpty(inRecords)){
                Map<Object, Object> map = Maps.newHashMap();
                map.put("name", "进厂");
                Object[] outData = new Object[chartVo.getXsxisData().length];
                for (int i = 0; i < chartVo.getXsxisData().length; i++) {
                    if(inRecords.containsKey(chartVo.getXsxisData()[i])){
                        outData[i] = inRecords.get(chartVo.getXsxisData()[i]).size();
                    } else {
                        outData[i] = null;
                    }
                }
                map.put("data", outData);
                seriesData.add(map);
            }
            chartVo.setSeriesData(seriesData);
        } else {
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setXsxisData(new Object[0]);
        }
        res.put("chart", chartVo);
        return res;
    }

    @Override
    public List<MapPointVo> pullPoints(String factoryId, String pointType) {
        // pointType=生产监控、煤气放散监控、在线监测、无组织监控、分表计电、视频监控
        List<MapPointVo> res = Lists.newArrayList();
        switch (pointType){
            case "门禁":
                List<PcFactoryAccessControl> accessControls = pcFactoryAccessControlMapper.selectList(new QueryWrapper<PcFactoryAccessControl>().eq("factory_id", factoryId));
                if (!CollectionUtils.isEmpty(accessControls)) {
                    res = accessControls.stream().map(p -> {
                        MapPointVo vo = new MapPointVo();
                        vo.setPointName(p.getAccessControlName());
                        vo.setPointCode(p.getAccessControlCode());
                        vo.setPointLng(new BigDecimal(p.getAccessControlLng()));
                        vo.setPointLat(new BigDecimal(p.getAccessControlLat()));
                        vo.setPointType("门禁");
                        return vo;
                    }).collect(Collectors.toList());
                }
                break;
            case "生产监控":
                // 设备类型(焦化:JL,烧结:SJJ,球团:SL,炼铁:GL,炼钢:ZL,白灰窑:LY,发电:FDJZ。ALL=全部)
                List<BasDevice> basDeviceList = basDeviceMapper.selectList(new QueryWrapper<BasDevice>().eq("factory_id", factoryId).isNotNull("lon").isNotNull("lat"));
                if (!CollectionUtils.isEmpty(basDeviceList)) {
                    List<BasDeviceSalAnalysis> basDeviceSalAnalyses = basDeviceSalAnalysisMapper.selectList(new QueryWrapper<BasDeviceSalAnalysis>().in("device_id", basDeviceList.stream().map(BasDevice::getDeviceId).distinct().collect(Collectors.toList())).eq("factory_id", factoryId));
                    Map<String, List<BasDeviceSalAnalysis>> analyMaps = CollectionUtils.isEmpty(basDeviceSalAnalyses) ? Maps.newHashMap() : basDeviceSalAnalyses.stream().collect(Collectors.groupingBy(BasDeviceSalAnalysis::getDeviceId));
                    res.addAll(basDeviceList.stream().map(p -> {
                        MapPointVo vo = new MapPointVo();
                        vo.setPointName(p.getName());
                        vo.setPointCode(p.getDeviceId());
                        vo.setPointLng(p.getLon());
                        vo.setPointLat(p.getLat());
                        vo.setPointType("生产监控");
                        // TODO 设备[前端取得是正常](默认)、生产、停产、离线
                        vo.setPointStatus(analyMaps.containsKey(p.getDeviceId()) ? analyMaps.get(p.getDeviceId()).get(0).getMonStatus() : "正常");
                        return vo;
                    }).collect(Collectors.toList()));
                }
                break;
            case "煤气放散监控":
                // DCS系统，就是钢铁行业高炉、转炉、焦炉，以及焦化行业焦炉的经纬度
                List<BasDevice> collect = basDeviceMapper.selectList(
                        new QueryWrapper<BasDevice>().eq("factory_id", factoryId).isNotNull("lon").isNotNull("lat")
                        .in("industry", "GT", "JH")
                        .in("type", "GLMQ", "MQGW", "GLMQG", "ZL")
                );
                if(!CollectionUtils.isEmpty(collect)){
                        List<BasDeviceSalAnalysis> basDeviceSalAnalyses = basDeviceSalAnalysisMapper.selectList(new QueryWrapper<BasDeviceSalAnalysis>().in("device_id", collect.stream().map(BasDevice::getDeviceId).distinct().collect(Collectors.toList())).eq("factory_id", factoryId));
                        Map<String, List<BasDeviceSalAnalysis>> analyMaps = CollectionUtils.isEmpty(basDeviceSalAnalyses) ? Maps.newHashMap() : basDeviceSalAnalyses.stream().collect(Collectors.groupingBy(BasDeviceSalAnalysis::getDeviceId));
                        if(!CollectionUtils.isEmpty(collect)){
                            res.addAll(collect.stream().map(p -> {
                                MapPointVo vo = new MapPointVo();
                                vo.setPointName(p.getName());
                                vo.setPointCode(p.getDeviceId());
                                vo.setPointLng(p.getLon());
                                vo.setPointLat(p.getLat());
                                vo.setPointType("煤气放散监控");
                                // TODO 正常放散、异常放散、未放散、离线/异常(默认)
                                vo.setPointStatus(analyMaps.containsKey(p.getDeviceId()) && !StringUtils.isEmpty(analyMaps.get(p.getDeviceId()).get(0).getCoalGasStatus()) ? analyMaps.get(p.getDeviceId()).get(0).getCoalGasStatus() : "离线/异常");
                                return vo;
                            }).collect(Collectors.toList()));
                        }
                }
                break;
            case "在线监测":
                List<PcOutlet> mapAirPointVos = pcOutletMapper.selectList(new QueryWrapper<PcOutlet>().eq("factory_id", factoryId).isNotNull("monitoring_point_name").isNotNull("outlet_lon").isNotNull("outlet_lat").eq("pollutant_type","4"));
                if (!CollectionUtils.isEmpty(mapAirPointVos)) {
                    res.addAll(mapAirPointVos.stream().map(p -> {
                        MapPointVo vo = new MapPointVo();
                        vo.setPointName(p.getMonitoringPointName());
                        vo.setPointCode(p.getId());
                        vo.setPointLng(p.getOutletLon());
                        vo.setPointLat(p.getOutletLat());
                        vo.setPointType("在线监测");
                        vo.setPointSubClass("未知");
                        // TODO 正常、预警/异常、超标、掉线(默认)
                        vo.setPointStatus(StringUtils.isEmpty(p.getOutletStatus()) ? "掉线" : p.getOutletStatus());

                        return vo;
                    }).collect(Collectors.toList()));
                }
                break;
            case "无组织监控":
                List<PcOutlet> wzzs = pcOutletMapper.selectList(new QueryWrapper<PcOutlet>().eq("factory_id", factoryId).isNotNull("outlet_lon").isNotNull("outlet_lat").isNotNull("monitoring_point_name").eq("pollutant_type", "3"));
                if (!CollectionUtils.isEmpty(wzzs)) {
                    res = wzzs.stream().map(p -> {
                        MapPointVo vo = new MapPointVo();
                        // 2.地图弹框中的无组织点位名称对应监测点位名称；
                        vo.setPointName(p.getMonitoringPointName());
                        vo.setPointCode(p.getId());
                        vo.setPointLng(p.getOutletLon());
                        vo.setPointLat(p.getOutletLat());
                        vo.setPointType("无组织监控");
                        vo.setPointSubClass(p.getOutletMonitorName());
                        // TODO 正常、报警、离线
                        vo.setPointStatus(StringUtils.isEmpty(p.getWzzStatus()) ? "离线" : p.getWzzStatus());
                        return vo;
                    }).collect(Collectors.toList());
                }
                break;
            case "分表计电":
                List<MapPointVo> fbjds = basDeviceSiteMapper.selectMapPoints(factoryId);
                if (!CollectionUtils.isEmpty(fbjds)) {
                    res = fbjds.stream().map(p -> {
                        p.setPointType("分表计电");
                        // 正常、停运、掉线
                        p.setPointStatus(StringUtil.isEmpty(p.getPointStatus()) ? "掉线" : p.getPointStatus());
                        return p;
                    }).collect(Collectors.toList());
                }
                break;
            case "视频监控":
                AmVideoDevFiQuery videoQuery = new AmVideoDevFiQuery();
                videoQuery.setFactoryId(factoryId);
                List<AmVideoDevFiVo.DevTypeGroup> groupList = amVideoDevFiService.getGroupList(videoQuery);
                if (!CollectionUtils.isEmpty(groupList)){
                    for (AmVideoDevFiVo.DevTypeGroup devTypeGroup : groupList) {
                        if(!CollectionUtils.isEmpty(devTypeGroup.getVideoDevFiVos())){
                            res.addAll(devTypeGroup.getVideoDevFiVos().stream().map(p -> {
                                MapPointVo vo = new MapPointVo();
                                vo.setPointName(p.getDevName());
                                vo.setPointCode(p.getId() == null ? null : p.getId().toString());
                                vo.setPointLng(p.getLonMap());
                                vo.setPointLat(p.getLatMap());
                                vo.setPointLocation(p.getLocation());
                                vo.setPointType("视频监控");
                                vo.setPointSubClass(devTypeGroup.getName());
                                return vo;
                            }).collect(Collectors.toList()));
                        }
                    }
                }
                break;
        }
        return res;
    }

    @Override
    public Map<String, Object> pullFbjdPop(String factoryId, String pointCode) {
        BasDeviceSite basDeviceSite = basDeviceSiteMapper.selectOne(new QueryWrapper<BasDeviceSite>().eq("id", pointCode).eq("factory_id", factoryId));
        if(basDeviceSite == null){
            throw new ServiceException("无法获取点位信息!");
        }
        Map<String, Object> res = Maps.newHashMap();
        ChartVo chartVo = new ChartVo();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        Date date = new Date();
        String now = format.format(date);
        // 近1天
        c.setTime(date);
        c.add(Calendar.DATE, - 1);
        Date d = c.getTime();
        String begin = format.format(d);
        List<MonElecReal> monElecReals = monElecRealMapper.selectList(new QueryWrapper<MonElecReal>().eq("device_site_id", basDeviceSite.getId()).between("data_time", d, date).isNotNull("active_power").orderByAsc("data_time"));
        if(!CollectionUtils.isEmpty(monElecReals)){
            monElecReals.forEach(item->{
                item.setDataTimeStr(DateUtils.parseDateToStr(DatePattern.NORM_DATETIME_MINUTE_PATTERN, item.getDataTime()));
            });
            chartVo.setLegendData(new Object[]{"功率", "用电量"});
//            monElecReals.stream().forEach(item -> item.setDataTimeStr(item.getDataTimeStr().substring(11, 16)));
//            chartVo.setXsxisData(monElecReals.stream().map(MonElecReal::getDataTimeStr).distinct().collect(Collectors.toList()).toArray(new Object[0]));
            List<String> qh = DateUtils.getRangeTimes("QH", d, date);
            chartVo.setXsxisData(qh.toArray());
            Map<String, List<MonElecReal>> hourDataMaps = monElecReals.stream().collect(Collectors.groupingBy(MonElecReal::getDataTimeStr));
            hourDataMaps.forEach((month,data)->{
                data.stream().collect(Collectors.toMap(MonElecReal::getDataTimeStr, a -> a, (o1, o2) -> {
                    o1.setActivePower(strToBigDecimal(o1.getActivePower()).add(strToBigDecimal(o2.getActivePower())).toString());
                    o1.setActivePowerQuantity(strToBigDecimal(o1.getActivePowerQuantity()).add(strToBigDecimal(o2.getActivePowerQuantity())).toString());
                    return o1;
                })).values();
            });

            List<BigDecimal> kwDatas = Lists.newArrayList();
            List<BigDecimal> wkhDatas = Lists.newArrayList();
            // TODO 分表计电的用电量用总有功电量示值计算，前后两个15分钟的总有功电量示值相减就是这15分钟的用电量
            // 用电量取总有功电量示值, 该字段存的是计算后的用电量. 数据接入程序计算.
            for (Object time : chartVo.getXsxisData()) {
                if(hourDataMaps.containsKey(time)){
                    kwDatas.add(new BigDecimal(hourDataMaps.get(time).get(0).getActivePower()));
                    wkhDatas.add(new BigDecimal(hourDataMaps.get(time).get(0).getActivePowerQuantity()));
                } else {
                    kwDatas.add(null);
                    wkhDatas.add(null);
                }
            }
            List<Map<Object, Object>> seriesData = Lists.newArrayList();
            //功率是总有功功率
            Map<Object, Object> map = Maps.newHashMap();
            map.put("name", chartVo.getLegendData()[0]);
            map.put("unit", "kW");
            map.put("data", kwDatas);
            seriesData.add(map);
            Map<Object, Object> wkhMaps = Maps.newHashMap();
            wkhMaps.put("name", chartVo.getLegendData()[1]);
            wkhMaps.put("unit", "kW·h");
            wkhMaps.put("data", wkhDatas);
            seriesData.add(wkhMaps);

            List<Map<Object, Object>> yaxisData = Lists.newArrayList();
            Map<Object, Object> ymap = Maps.newHashMap();
            ymap.put("name", "kW");
            List<BigDecimal> kws = kwDatas.stream().filter(item -> item != null).collect(Collectors.toList());
            ymap.put("interval", toInterval(kws.stream().max((x1, x2) -> x1.compareTo(x2)).get(), chartVo.getXsxisData().length));
            ymap.put("min", 0);
            ymap.put("max", kws.stream().max((x1, x2) -> x1.compareTo(x2)).get());
            ymap.put("axisLabelUnit", "");
            yaxisData.add(ymap);
            Map<Object, Object> ywkhmap = Maps.newHashMap();
            ywkhmap.put("name", "kW·h");
            List<BigDecimal> wkhs = wkhDatas.stream().filter(item -> item != null).collect(Collectors.toList());
            ywkhmap.put("interval", toInterval(wkhs.stream().max((x1, x2) -> x1.compareTo(x2)).get(), chartVo.getXsxisData().length));
            ywkhmap.put("min", 0);
            ywkhmap.put("max", wkhs.stream().max((x1, x2) -> x1.compareTo(x2)).get());
            ywkhmap.put("axisLabelUnit", "");
            yaxisData.add(ywkhmap);
            chartVo.setSeriesData(seriesData);
            chartVo.setYaxisData(yaxisData);
            // 分表计电的状态通过功率判断，功率为0是停运，接不到数据是掉线，其他正常
            /*if(CollectionUtils.isEmpty(wkhDatas)){
                pointStatus = "掉线";
            } else {
                if(ywkhmap.get("max").equals("0")){
                    pointStatus = "停运";
                }
            }*/
        } else {
            chartVo.setLegendData(new Object[]{"功率", "用电量"});
            chartVo.setXsxisData(new Object[]{});
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setYaxisData(Lists.newArrayList());
        }
        // 无数据默认补全x轴
        if(chartVo.getXsxisData().length == 0){
            chartVo.setXsxisData(CustomDateUtil.getAllHours(d, date, CustomDateUtil.HOUR_PATTERN).stream().toArray());
        }
        if(CollectionUtils.isEmpty(chartVo.getSeriesData()) && chartVo.getLegendData().length != 0){
            for (Object legendDatum : chartVo.getLegendData()) {
                Map<Object, Object> map = Maps.newHashMap();
                map.put("name", legendDatum);
                map.put("unit", "");
                List<Object> sd = Lists.newArrayList();
                for (int i = 0; i < chartVo.getXsxisData().length; i++) {
                    sd.add("");
                }
                map.put("data", sd);
                chartVo.getSeriesData().add(map);
            }
        }
        res.put("chart", chartVo);
        // 点位基本信息
        res.put("pointName", basDeviceSite.getName());
        // TODO 这个和上面那个类似，就是说明这个监测点位监测的是生产设施的用电，还是治理设施的用电。如果是生产设施的用电，那就是生产监测点位。对应关系同上
        res.put("pointType", basDeviceSite.getType());// 生产监测点位
        // TODO 对应装备名称 就是分表计电本身对应的治理设施或生产设施名称，分表计电系统有这个对应关系。
        res.put("equipName", basDeviceSite.getEquipName());// 对应装备名称
        res.put("pointStatus", StringUtil.isEmpty(basDeviceSite.getStatus()) ? "掉线" : basDeviceSite.getStatus());// 正常/停运/掉线
        return res;
        //静态数据
        //return fbjdStatisData(pointName);
    }

    private BigDecimal toInterval(BigDecimal max, Integer size){
        return max.divide(new BigDecimal(size),1,BigDecimal.ROUND_HALF_UP);
    }

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

    @Override
    public Map<String, Object> pullWzzPop(String factoryId, String pointCode) {
        // 查询排口信息
        PcOutlet pcOutlet = pcOutletMapper.selectOne(new QueryWrapper<PcOutlet>().eq("id", pointCode));
        if(pcOutlet == null){
            throw new ServiceException("无法获取点位信息");
        }
        LocalDateTime nowTo = LocalDateTime.now();
        String startTime=nowTo.format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00")
        );
        String endTime= nowTo.format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59")
        );
        List<String> amProblemFi=amProblemFiMapper.selectByLastTimeAlarm(pointCode,startTime,endTime);

        List<PcIndustry> pcIndustries = pcIndustryMapper.selectList(new QueryWrapper<>());
        Map<String, List<PcIndustry>> pcIndustriesMaps = CollectionUtils.isEmpty(pcIndustries) ? Maps.newHashMap() : pcIndustries.stream().collect(Collectors.groupingBy(PcIndustry::getIndusCode));
        Map<String, Object> res = Maps.newHashMap();
        // 点位基本信息
        res.put("pointName", pcOutlet.getMonitoringPointName());
        // 设备类型编码转名称
        res.put("pointType", pcIndustriesMaps.containsKey(pcOutlet.getOutletMonitorName()) ? pcIndustriesMaps.get(pcOutlet.getOutletMonitorName()).get(0).getIndusName() : pcOutlet.getOutletMonitorName());
        res.put("wzzVentCode", pcOutlet.getStationId());
        res.put("pointStatus", pcOutlet.getWzzStatus());
        res.put("alarm", String.join(";",amProblemFi));
        ChartVo chartVo = new ChartVo();
        // 查询排口污染物信息
        List<PcFactoryPollutant> factoryPollutants = pcFactoryPollutantMapper.selectList(new QueryWrapper<PcFactoryPollutant>().eq("outlet_id", pcOutlet.getId()));
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        Date date = new Date();
        String now = format.format(date);
        // 近1天
        c.setTime(date);
        c.add(Calendar.DATE, - 1);
        Date d = c.getTime();
        if(!CollectionUtils.isEmpty(factoryPollutants)){
            SEnvGasRealQuery sEnvGasRealQuery = new SEnvGasRealQuery();
            String begin = format.format(d);
            sEnvGasRealQuery.setOutletId(pcOutlet.getId());
            sEnvGasRealQuery.setDataType(TimeTypeEnum.HOUR.getCode());
            sEnvGasRealQuery.setMonitoringStartTime(begin);
            sEnvGasRealQuery.setMonitoringEndTime(now);
            sEnvGasRealQuery.setAscOrDesc("asc");
            EChartsVO charData = sEnvGasRealService.getCharData(sEnvGasRealQuery);
            if(charData != null && !CollectionUtils.isEmpty(charData.getSeries()) && !CollectionUtils.isEmpty(charData.getXData())){
                // 查询污染物信息
                List<PcPollutant> pcPollutants = pcPollutantMapper.selectList(new QueryWrapper<PcPollutant>().in("id", factoryPollutants.stream().map(PcFactoryPollutant::getPollutantId).distinct().collect(Collectors.toSet())));
                if(!CollectionUtils.isEmpty(pcPollutants) || "3".equals(pcOutlet.getPollutantType())){
                    List<String> polls = pcPollutants.stream().map(PcPollutant::getPollName).distinct().collect(Collectors.toList());
                    chartVo.setLegendData(polls.stream().toArray());
                    List<EChartsVO.SeriesObj> series = charData.getSeries();
                    List<String> xData = charData.getXData();
                    List<Map<Object, Object>> seriesData = Lists.newArrayList();
                    Map<String, List<EChartsVO.SeriesObj>> pDatas = series.stream().collect(Collectors.groupingBy(EChartsVO.SeriesObj::getName));
                    // 如果是无组织排口类型走以下逻辑 否则走原逻辑（因为排口关联的污染物与企业分类档案里的无组织监控页面的表格，列名，对不上）
                    if ("3".equals(pcOutlet.getPollutantType())) {
                        polls = series.stream().map(EChartsVO.SeriesObj::getName).collect(Collectors.toList());
                        chartVo.setLegendData(polls.stream().toArray());
                    }
                    for (String poll : polls) {
                        Map<Object, Object> map = Maps.newHashMap();
                        if(pDatas.containsKey(poll)){
                            EChartsVO.SeriesObj seriesObj = pDatas.get(poll).get(0);
                            map.put("name", seriesObj.getName());
                            map.put("unit", seriesObj.getUnit());
                            map.put("data", seriesObj.getValues());
                        } else {
                            map.put("name", poll);
                            map.put("unit", "");
                            map.put("data", Lists.newArrayList());
                        }
                        seriesData.add(map);
                    }
                    chartVo.setSeriesData(seriesData);
                    chartVo.setYaxisData(Lists.newArrayList());
            /*xData.stream().forEach(item->item.substring(11, 13));
            for (int i = 0; i < xData.size(); i++) {
                xData.set(i, xData.get(i).substring(11, 13));
            }*/
                    chartVo.setXsxisData(xData.stream().toArray());
                }
            } else {
                chartVo.setLegendData(new Object[]{});
                chartVo.setXsxisData(new Object[]{});
                chartVo.setSeriesData(Lists.newArrayList());
                chartVo.setYaxisData(Lists.newArrayList());
            }
        } else {
            chartVo.setLegendData(new Object[]{});
            chartVo.setXsxisData(new Object[]{});
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setYaxisData(Lists.newArrayList());
        }
        // 无数据默认补全x轴
        if(chartVo.getXsxisData().length == 0){
            chartVo.setXsxisData(CustomDateUtil.getAllHours(d, date, CustomDateUtil.HOUR_PATTERN).stream().toArray());
        }
        res.put("chart", chartVo);
        return res;
        //静态数据
        //return wzzStatisData(pointCode);
    }

    @Override
    public Map<String, Object> pullOnlinePop(String factoryId, String pointCode) {
        // 查询排口信息
        PcOutlet pcOutlet = pcOutletMapper.selectOne(new QueryWrapper<PcOutlet>().eq("id", pointCode).eq("factory_id", factoryId));
        if(pcOutlet == null){
            throw new ServiceException("无法获取点位信息");
        }
        LocalDateTime nowTo = LocalDateTime.now();
        String startTime=nowTo.format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00")
        );
        String endTime= nowTo.format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59")
        );
        List<String> amProblemFi=amProblemFiMapper.selectByLastTimeAlarm(pointCode,startTime,endTime);
        Map<String, Object> res = Maps.newHashMap();
        // 点位基本信息
        res.put("pointName", pcOutlet.getOutletName());
        res.put("pointCode", pcOutlet.getOutletCode());
        if(pcOutlet.getPollutantType().equals("1")){
            res.put("pointType", pcOutlet.getOutletTypes().equals("1") ? "废气主要排口" : pcOutlet.getOutletTypes().equals("2") ? "废气一般排口" : "未知");
        } else if (pcOutlet.getPollutantType().equals("2")){
            res.put("pointType", pcOutlet.getEmissionsForm().equals("直接排放") ? "废水直接排放口" : pcOutlet.getEmissionsForm().equals("间接排放") ? "废水间接排放口" : "未知");
        }
        res.put("monitorName", pcOutlet.getMonitoringPointName());//"监测点位名称"
        res.put("pointStatus", StringUtils.isEmpty(pcOutlet.getOutletStatus()) ? "掉线" : pcOutlet.getOutletStatus());
        res.put("alarm", String.join(";",amProblemFi));
        ChartVo chartVo = new ChartVo();
        // 查询排口污染物信息
        List<PcFactoryPollutant> factoryPollutants = pcFactoryPollutantMapper.selectList(new QueryWrapper<PcFactoryPollutant>().eq("factory_id", factoryId).eq("outlet_id", pcOutlet.getId()));
        if(CollectionUtils.isEmpty(factoryPollutants)){
            chartVo.setLegendData(new Object[]{});
            chartVo.setXsxisData(new Object[]{});
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setYaxisData(Lists.newArrayList());
            res.put("chart", chartVo);
            return res;
        }
        // 查询污染物信息
        List<PcPollutant> pcPollutants = pcPollutantMapper.selectList(new QueryWrapper<PcPollutant>().in("id", factoryPollutants.stream().map(PcFactoryPollutant::getPollutantId).distinct().collect(Collectors.toSet())));
        if(CollectionUtils.isEmpty(pcPollutants)){
            chartVo.setLegendData(new Object[]{});
            chartVo.setXsxisData(new Object[]{});
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setYaxisData(Lists.newArrayList());
            res.put("chart", chartVo);
            return res;
        }
        Map<String, List<PcPollutant>> pollDatas = pcPollutants.stream().collect(Collectors.groupingBy(PcPollutant::getPollName));
        // 查询管控要求(获取污染物浓度限值)
        List<PcControlRequirements> pcControlRequirements = pcControlRequirementsMapper.selectList(new QueryWrapper<PcControlRequirements>().eq("factory_id", factoryId).eq("outlet_id", pcOutlet.getId()));
        Map<String, List<PcControlRequirements>> controlDatas = CollectionUtils.isEmpty(pcControlRequirements) ? Maps.newHashMap() : pcControlRequirements.stream().collect(Collectors.groupingBy(PcControlRequirements::getPollutantId));
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        Date date = new Date();
        String now = format.format(date);
        // 近1天
        c.setTime(date);
        c.add(Calendar.DATE, - 1);
        Date d = c.getTime();
        String begin = format.format(d);
        EChartsVO charData = new EChartsVO();
        if(pcOutlet.getPollutantType().equals("1")) {
            SEnvGasMonRealQuery sEnvGasMonRealQuery = new SEnvGasMonRealQuery();
            sEnvGasMonRealQuery.setOutletId(pcOutlet.getId());
            sEnvGasMonRealQuery.setDataType(TimeTypeEnum.HOUR.getCode());
            sEnvGasMonRealQuery.setMonitoringStartTime(begin);
            sEnvGasMonRealQuery.setMonitoringEndTime(now);
            charData = envGasMonRealService.getCharData(sEnvGasMonRealQuery);
        } else if (pcOutlet.getPollutantType().equals("2")){
            SEnvWaterMonRealQuery sEnvWaterMonRealQuery = new SEnvWaterMonRealQuery();
            sEnvWaterMonRealQuery.setOutletId(pcOutlet.getId());
            sEnvWaterMonRealQuery.setDataType(TimeTypeEnum.HOUR.getCode());
            sEnvWaterMonRealQuery.setMonitoringStartTime(begin);
            sEnvWaterMonRealQuery.setMonitoringEndTime(now);
            charData = envWaterMonRealService.getCharData(sEnvWaterMonRealQuery);
        } else if (pcOutlet.getPollutantType().equals("3")){
            SEnvWaterMonRealQuery sEnvWaterMonRealQuery = new SEnvWaterMonRealQuery();
            sEnvWaterMonRealQuery.setOutletId(pcOutlet.getId());
            sEnvWaterMonRealQuery.setDataType(TimeTypeEnum.HOUR.getCode());
            sEnvWaterMonRealQuery.setMonitoringStartTime(begin);
            sEnvWaterMonRealQuery.setMonitoringEndTime(now);
            charData = envWaterMonRealService.getCharData(sEnvWaterMonRealQuery);
        } else if (pcOutlet.getPollutantType().equals("4")){
            //在线监测无法区分监测点类型，数据全查
            if(pcOutlet.getPollutantOutletType().equals("1")){
                SEnvGasMonRealQuery sEnvGasMonRealQuery = new SEnvGasMonRealQuery();
                sEnvGasMonRealQuery.setOutletId(pcOutlet.getId());
                sEnvGasMonRealQuery.setDataType(TimeTypeEnum.HOUR.getCode());
                sEnvGasMonRealQuery.setMonitoringStartTime(begin);
                sEnvGasMonRealQuery.setMonitoringEndTime(now);
                charData = envGasMonRealService.getCharData(sEnvGasMonRealQuery);
            }else{
                SEnvWaterMonRealQuery sEnvWaterMonRealQuery = new SEnvWaterMonRealQuery();
                sEnvWaterMonRealQuery.setOutletId(pcOutlet.getId());
                sEnvWaterMonRealQuery.setDataType(TimeTypeEnum.HOUR.getCode());
                sEnvWaterMonRealQuery.setMonitoringStartTime(begin);
                sEnvWaterMonRealQuery.setMonitoringEndTime(now);
                charData = envWaterMonRealService.getCharData(sEnvWaterMonRealQuery);
            }
        }
        if(charData != null && !CollectionUtils.isEmpty(charData.getSeries()) && !CollectionUtils.isEmpty(charData.getXData())){
            //List<String> polls = pcPollutants.stream().map(PcPollutant::getPollName).distinct().collect(Collectors.toList());
            List<EChartsVO.SeriesObj> series = charData.getSeries();
            List<String> xData = charData.getXData();
            List<Map<Object, Object>> seriesData = Lists.newArrayList();
            Map<String, List<EChartsVO.SeriesObj>> pDatas = series.stream().collect(Collectors.groupingBy(EChartsVO.SeriesObj::getName));
            List<String> polls = new ArrayList<>(pDatas.keySet());
            chartVo.setLegendData(polls.stream().toArray());
            for (String poll : polls) {
                Map<Object, Object> map = Maps.newHashMap();
                if(pDatas.containsKey(poll)){
                    EChartsVO.SeriesObj seriesObj = pDatas.get(poll).get(0);
                    map.put("name", seriesObj.getName());
                    map.put("unit", seriesObj.getUnit());
                    map.put("data", seriesObj.getValues());
                    List<BigDecimal> data = Lists.newArrayList();
                    for (int i = 0; i < seriesObj.getValues().size(); i++) {
                        data.add(seriesObj.getValues().get(i)!=null?new BigDecimal(seriesObj.getValues().get(i).toString()) : BigDecimal.ZERO);
                    }
                    BigDecimal dataMax = data.stream().max((x1, x2) -> x1.compareTo(x2)).get();
                    BigDecimal limitValue = null;
                    if(pollDatas.containsKey(seriesObj.getName())){
                        if(controlDatas.containsKey(pollDatas.get(seriesObj.getName()).get(0).getId())){
                            String permissibleConcentrationLimHour = controlDatas.get(pollDatas.get(seriesObj.getName()).get(0).getId()).get(0).getPermissibleConcentrationLimHour();
                            if(!StringUtil.isEmpty(permissibleConcentrationLimHour)){
                                limitValue = new BigDecimal(permissibleConcentrationLimHour);
                            }
                        }
                    }
                    map.put("max", limitValue);
                    map.put("replacey", limitValue != null && limitValue.compareTo(dataMax) != -1 ? true : false);
                } else {
                    map.put("name", poll);
                    map.put("unit", "");
                    map.put("max", 0);
                    map.put("replacey", false);
                    map.put("data", Lists.newArrayList());
                }
                seriesData.add(map);
            }
            chartVo.setSeriesData(seriesData);
            chartVo.setYaxisData(Lists.newArrayList());
            /*xData.stream().forEach(item->item.substring(11, 16));
            for (int i = 0; i < xData.size(); i++) {
                xData.set(i, xData.get(i).substring(11, 16));
            }*/
            chartVo.setXsxisData(xData.stream().toArray());
        } else {
            chartVo.setLegendData(new Object[]{});
            chartVo.setXsxisData(new Object[]{});
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setYaxisData(Lists.newArrayList());
        }
        res.put("chart", chartVo);
        return res;
        //静态数据
        //return onlineStatisData(pointCode);
    }

    @Override
    public Map<String, Object> pullProducePop(String factoryId, String pointCode) {
        // 查询设备信息
        BasDevice basDevice = basDeviceMapper.selectOne(new QueryWrapper<BasDevice>().eq("device_id", pointCode).eq("factory_id", factoryId));
        if(basDevice == null){
            throw new ServiceException("无法获取设备信息");
        }
        IotDeviceType iotDeviceType = iotDeviceTypeMapper.selectOne(new QueryWrapper<IotDeviceType>().eq("device_code", basDevice.getType()).eq("industry_code", basDevice.getIndustry()).eq("delete_flag", 0));
        BasDeviceSalAnalysis basDeviceSalAnalysis = basDeviceSalAnalysisMapper.selectOne(new QueryWrapper<BasDeviceSalAnalysis>().eq("device_id", basDevice.getDeviceId()).eq("factory_id", factoryId));
        Map<String, Object> res = Maps.newHashMap();
        // 点位基本信息
        res.put("pointName", basDevice.getName());
        res.put("pointCode", pointCode);// 排污许可设备编号
        res.put("pointType", iotDeviceType != null ? iotDeviceType.getName() : "未知");
        res.put("gycs", basDevice.getCraftParam());
        res.put("pointStatus", basDeviceSalAnalysis != null ? basDeviceSalAnalysis.getMonStatus() : "设备");
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar c = Calendar.getInstance();
        Date date = new Date();
        String now = format.format(date);
        // 近1天
        c.setTime(date);
        c.add(Calendar.DATE, - 1);
        Date d = c.getTime();
        String begin = format.format(d);
        EChartsVO deviceChart = basDeviceService.getDeviceChart(basDevice.getDeviceId(), begin, now);
        ChartVo chartVo = new ChartVo();
        if(deviceChart != null){
            chartVo.setLegendData(CollectionUtils.isEmpty(deviceChart.getLegendData()) ? new Object[]{} : deviceChart.getLegendData().stream().toArray());
            chartVo.setXsxisData(CollectionUtils.isEmpty(deviceChart.getXData()) ? new Object[]{} : deviceChart.getXData().stream().toArray());
            if(!CollectionUtils.isEmpty(deviceChart.getSeries())){
                if(ArrayUtil.isEmpty(chartVo.getLegendData())){
                    chartVo.setLegendData(deviceChart.getSeries().stream().map(EChartsVO.SeriesObj::getName).collect(Collectors.toList()).stream().toArray());
                }
                List<Map<Object, Object>> seriesData = Lists.newArrayList();
                List<Map<Object, Object>> yaxisData = Lists.newArrayList();
                deviceChart.getSeries().stream().forEach(item->{
                    Map<Object, Object> map = Maps.newHashMap();
                    map.put("name", item.getName());
                    map.put("unit", item.getUnit());
                    map.put("data", item.getValues());
                    seriesData.add(map);
                    Map<Object, Object> ymap = Maps.newHashMap();
                    ymap.put("name", item.getName());
                    ymap.put("unit", item.getUnit());
                    List<BigDecimal> data = Lists.newArrayList();
                    if(!CollectionUtils.isEmpty(item.getValues()) && !CollectionUtils.isEmpty(deviceChart.getXData())){
                        for (int i = 0; i < item.getValues().size(); i++) {
                            data.add(item.getValues().get(i)!=null?new BigDecimal(item.getValues().get(i).toString()) : BigDecimal.ZERO);
                        }
                        ymap.put("interval", toInterval(data.stream().max((x1, x2) -> x1.compareTo(x2)).get(), deviceChart.getXData().size()));
                        ymap.put("min", 0);
                        ymap.put("max", data.stream().max((x1, x2) -> x1.compareTo(x2)).get());
                    } else {
                        ymap.put("interval", "");
                        ymap.put("min", 0);
                        ymap.put("max", "");
                    }
                    ymap.put("axisLabelUnit", "");
                    yaxisData.add(ymap);
                });
                chartVo.setSeriesData(seriesData);
                chartVo.setYaxisData(yaxisData);
            }
        } else {
            chartVo.setLegendData(new Object[]{});
            chartVo.setXsxisData(new Object[]{});
            chartVo.setSeriesData(Lists.newArrayList());
            chartVo.setYaxisData(Lists.newArrayList());
        }
        res.put("chart", chartVo);
        return res;
        // 静态数据
        // return produceStatisData(pointCode);
    }

    @Override
    public Map<String, Object> pullCoalGasPop(String factoryId, String pointCode) {
        BasDevice basDevice = basDeviceMapper.selectOne(new QueryWrapper<BasDevice>().eq("device_id", pointCode).eq("factory_id", factoryId));
        if(basDevice == null){
            throw new ServiceException("无法获取设备信息!");
        }
        BasDeviceSalAnalysis basDeviceSalAnalysis = basDeviceSalAnalysisMapper.selectOne(new QueryWrapper<BasDeviceSalAnalysis>().eq("device_id", basDevice.getDeviceId()).eq("factory_id", factoryId));
        IotDeviceType iotDeviceType = iotDeviceTypeMapper.selectOne(new QueryWrapper<IotDeviceType>().eq("device_code", basDevice.getType()).eq("industry_code", basDevice.getIndustry()).eq("delete_flag", 0));
        Map<String, Object> res = Maps.newHashMap();
        // 点位基本信息
        res.put("pointName", basDevice.getName());
        res.put("pointCode", basDevice.getDeviceId());
        res.put("pointType", iotDeviceType != null ? iotDeviceType.getName() : "未知");// 设备类型
        res.put("pointStatus", basDeviceSalAnalysis != null ? basDeviceSalAnalysis.getCoalGasStatus() : "离线/异常");// 当前运行状态

        Calendar c = Calendar.getInstance();
        Date date = new Date();
        // 近1天
        c.setTime(date);
        c.add(Calendar.DATE, - 1);
        Date d = c.getTime();
        QueryWrapper<SRaRealTimeAnalysisCo> wrapper=new QueryWrapper<SRaRealTimeAnalysisCo>();
        wrapper.eq(cn.cecep.talroad.common.core.utils.StringUtils.isNotEmpty(basDevice.getDeviceId()), "device_id", basDevice.getDeviceId());
        wrapper.ge("analyse_time", d);
        wrapper.le("analyse_time", date);
        wrapper.orderByAsc("diffuse_end_time");
        List<SRaRealTimeAnalysisCo> sRaRealTimeAnalysisRuns = sRaRealTimeAnalysisCoMapper.selectList(wrapper);
        if(CollectionUtil.isNotEmpty(sRaRealTimeAnalysisRuns)){
            res.put("pointStatus", sRaRealTimeAnalysisRuns.get(sRaRealTimeAnalysisRuns.size()-1).getDiffuse());
        }
        Map<String, String> timeStatusMap = sRaRealTimeAnalysisRuns.stream().filter(o->o.getDiffuseStatus()!=null).collect(Collectors.toMap(o ->  DateUtil.format(o.getDiffuseEndTime(),DatePattern.NORM_DATETIME_MINUTE_FORMATTER), o ->  o.getDiffuseStatus(), (o1, o2) -> o1));
        // x轴数据
        List<String> xdata = DateUtils.getRangeTimes("M", d, date);

        EChartsVO.SeriesObj ser1 = new EChartsVO.SeriesObj();
        ser1.setName("正常放散");
        ser1.setProp("1");
        ser1.setValues(new ArrayList<>());

        EChartsVO.SeriesObj ser2 = new EChartsVO.SeriesObj();
        ser2.setName("异常放散");
        ser2.setProp("2");
        ser2.setValues(new ArrayList<>());

        EChartsVO.SeriesObj ser3 = new EChartsVO.SeriesObj();
        ser3.setName("未放散");
        ser3.setProp("3");
        ser3.setValues(new ArrayList<>());

        EChartsVO.SeriesObj ser4 = new EChartsVO.SeriesObj();
        ser4.setName("离线");
        ser4.setProp("4");
        ser4.setValues(new ArrayList<>());

        EChartsVO.SeriesObj ser5 = new EChartsVO.SeriesObj();
        ser5.setName("异常");
        ser5.setProp("5");
        ser5.setValues(new ArrayList<>());

        EChartsVO chartsVO = new EChartsVO();
        chartsVO.setXData(xdata);
        chartsVO.setSeries(Arrays.asList(ser1, ser2, ser3, ser4,ser5));

        /*
            填充系列值
         */
        // 遍历x轴，保证系列值与x轴刻度一一对应
        for (String time : xdata) {
            String status = timeStatusMap.get(time);

            for (EChartsVO.SeriesObj ser : chartsVO.getSeries()) {
                // 若系列的prop属性与状态码相等，则设置系列值为状态码，否则填充null
                if (ser.getProp().equals(status)) {
                    ser.getValues().add(status);
                } else {
                    ser.getValues().add(null);
                }
            }
        }
        res.put("chart", chartsVO);
        return res;
        // 静态数据
        // return coalGasStatisData(pointCode);
    }

    @Override
    public List<MapPointVo> coalMapPoints(String name) {
        List<MapPointVo> list = basDeviceMapper.selectCoalMapPoints(name);
        return list;
    }

}
