package cn.cecep.talroad.service.impl;

import cn.cecep.talroad.common.core.domain.R;
import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.common.security.utils.SecurityUtils;
import cn.cecep.talroad.domain.SEnvGasReal;
import cn.cecep.talroad.enums.TimeTypeEnum;
import cn.cecep.talroad.feign.BaseRegionService;
import cn.cecep.talroad.mapper.SEnvGasRealMapper;
import cn.cecep.talroad.service.ISEnvGasRealService;
import cn.cecep.talroad.vo.AmProblemFiVo;
import cn.cecep.talroad.vo.EChartsVO;
import cn.cecep.talroad.vo.SysBasRegion;
import cn.cecep.talroad.vo.analysis.FactoryOutletStaticsVo;
import cn.cecep.talroad.vo.homepage.MonitoringPointWarningVo;
import cn.cecep.talroad.vo.homepage.OverviewUnorganizedMonitorsVo;
import cn.cecep.talroad.vo.homepage.RegionalOnlineMonitoringVo;
import cn.cecep.talroad.vo.query.EffectiveMonitoringRateQuery;
import cn.cecep.talroad.vo.query.SEnvGasRealQuery;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 无组织监控数据Service业务层处理
 *
 * @author szhpt
 * @date 2023-01-10*/
@Service
public class SEnvGasRealServiceImpl extends ServiceImpl<SEnvGasRealMapper,SEnvGasReal> implements ISEnvGasRealService
{
    @Autowired
    private SEnvGasRealMapper sEnvGasRealMapper;
    @Autowired
    @Qualifier("baseRegionService")
    private BaseRegionService baseRegionService;
    /**
     * 查询无组织监控数据列表
     *
     * @param sEnvGasReal 无组织监控数据
     * @return 无组织监控数据
     */
    @Override
    public List<SEnvGasReal> selectSEnvGasRealList(SEnvGasReal sEnvGasReal)
    {
        return sEnvGasRealMapper.selectSEnvGasRealList(sEnvGasReal);
    }

    @Override
    public EChartsVO getCharData(SEnvGasRealQuery sEnvGasReal) {
        // 结束日期格式补全，解决查询出的数据不包含结束日期的情况
        if (StringUtils.isNotEmpty(sEnvGasReal.getMonitoringEndTime())) {
            Date date = DateUtils.parseDate(sEnvGasReal.getMonitoringEndTime());
            sEnvGasReal.setMonitoringEndTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", date));
        }
        // x轴数据
        List<String> xdata = DateUtils.getRangeTimes(sEnvGasReal.getDataType(), sEnvGasReal.getMonitoringStartTime(), sEnvGasReal.getMonitoringEndTime());

        List<SEnvGasReal> sEnvGasReals = sEnvGasRealMapper.selectList(SEnvGasRealQuery.createLambdaQueryWrapper(sEnvGasReal));

        // 以日期为key,转为map 日期格式要保证与x轴格式一样
        Map<String, SEnvGasReal> gasRealMap = sEnvGasReals.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 (sEnvGasReal.getPollutantVos() != null) {
            // 去除掉prop属性为空的，并且通过map去重
            LinkedHashMap<String, AmProblemFiVo.PollutantVo> pollutantVoLinkedHashMap = sEnvGasReal.getPollutantVos().stream()
                    .filter(o -> o.getProp() != null)
                    .collect(Collectors.toMap(o -> o.getProp(), o -> o,
                            // 保留第一个
                            (o1, o2) -> o1,
                            // 保持顺序不变
                            LinkedHashMap::new));
            sEnvGasReal.setPollutantVos(new ArrayList<>(pollutantVoLinkedHashMap.values()));

            for (AmProblemFiVo.PollutantVo pollutantVo : sEnvGasReal.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 -> {
                    SEnvGasReal gasReal = gasRealMap.get(o);
                    if (gasReal == null) {
                        return null;
                    }
                    return BeanUtil.getProperty(gasReal, ser.getProp());
                }).collect(Collectors.toList());
                ser.setValues(values);

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

                series.add(ser);

                /*
                    若污染物指定了上下限，还需要生成上下限的曲线图
                 */
                if (pollutantVo.getPollutantLimitMap() != 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");

                    for (EChartsVO.SeriesObj seriesObj : Arrays.asList(lowerLimit, upperLimit)) {
                        // 填充曲线图系列值。遍历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);

                        series.add(seriesObj);
                    }

                    // 由于当前遍历的监测参数存在上下限系列，设置系列类型为“problem”，前端会通过该属性特殊渲染
                    ser.setSeriesType("problem");
                }
            }
        } else { // 未指定监测参数，默认展示所有的

            for (PollutantEnum pollutantEnum : PollutantEnum.values()) {
                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 -> {
                    SEnvGasReal gasReal = gasRealMap.get(o);
                    if (gasReal == null) {
                        return null;
                    }
                    return BeanUtil.getProperty(gasReal, ser.getProp());
                }).collect(Collectors.toList());
                ser.setValues(values);
                series.add(ser);
            }

        }

        EChartsVO chartsVO = new EChartsVO();
        chartsVO.setXData(xdata);
        chartsVO.setSeries(series);
        return chartsVO;
    }

    @Override
    public OverviewUnorganizedMonitorsVo overviewUnorganizedMonitors() {
        String regionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }
        return sEnvGasRealMapper.overviewUnorganizedMonitors(regionCodes);
    }

    @Override
    public EChartsVO monitoringPointWarning(EffectiveMonitoringRateQuery query) {
        String regionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }
        query.setRegionCodes(regionCodes);
        MonitoringPointWarningVo monitorsVo=sEnvGasRealMapper.monitoringPointWarning(query);
        EChartsVO eChartsVO=new EChartsVO();
        List<EChartsVO.SeriesObj> items= new ArrayList<>();
        EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
        ser.setName("报警");
        ser.setValues(new ArrayList<>());
        items.add(ser);
        EChartsVO.SeriesObj ser1 = new EChartsVO.SeriesObj();
        ser1.setName("预警");
        ser1.setValues(new ArrayList<>());
        items.add(ser1);
        EChartsVO.SeriesObj ser2 = new EChartsVO.SeriesObj();
        ser2.setName("异常");
        ser2.setValues(new ArrayList<>());
        items.add(ser2);
        items.get(0).getValues().add(monitorsVo.getGasMonitoringExceeding());
        items.get(1).getValues().add(monitorsVo.getGasMonitoringWarning());
        items.get(2).getValues().add(monitorsVo.getGasMonitoringAbnormal());
        eChartsVO.setSeries(items);
        return eChartsVO;
    }

    @Override
    public List<RegionalOnlineMonitoringVo> regionalOnlineMonitoring(EffectiveMonitoringRateQuery query) {
        String regionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> rs = baseRegionService.getRegionCodeListChild(regionCode);
        if(rs.getCode()==200){
            regionCodes=rs.getData();
        }
        query.setRegionCodes(regionCodes);
        List<SysBasRegion> regionArr=new ArrayList<>();
        R<List<SysBasRegion>> r = baseRegionService.getRegionList(regionCode);
        if(r.getCode()==200){
            regionArr=r.getData();
        }
        //封装数据
        List<RegionalOnlineMonitoringVo> regionalOnlineMonitoringVos=new ArrayList<>();
        regionArr.forEach(item->{
            RegionalOnlineMonitoringVo chil=new RegionalOnlineMonitoringVo();
            chil.setRegionName(item.getRegionName());
            chil.setDistrictCode(item.getRegionCode());
            regionalOnlineMonitoringVos.add(chil);
        });
        //监测点位数量
        List<RegionalOnlineMonitoringVo> numberMonitors= sEnvGasRealMapper.numberMonitoringPoints(query);
        //有效监测率
        List<RegionalOnlineMonitoringVo> monitoringRates= sEnvGasRealMapper.monitoringRate(query);
        monitoringRates.forEach(item->{
            if((BigDecimal.ZERO).compareTo(item.getTotal()) != 0 ){
                item.setMonitoringRate(item.getDivisor().divide(item.getTotal(),2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString()+"%");
            }
        });
        Map<String, RegionalOnlineMonitoringVo> monitoringRatesMap = monitoringRates.stream().collect(Collectors.toMap(RegionalOnlineMonitoringVo::getDistrictCode, a -> a,(k1, k2)->k1));
        //超标率
        List<RegionalOnlineMonitoringVo> excessRates= sEnvGasRealMapper.excessRate(query);
        excessRates.forEach(item->{
            if(monitoringRatesMap.containsKey(item.getDistrictCode())){
                BigDecimal total = monitoringRatesMap.get(item.getDistrictCode()).getTotal();
                if((BigDecimal.ZERO).compareTo(total) != 0 ){
                    item.setExcessRate(item.getDivisor().divide(total,2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString()+"%");
                }
            }else {
                item.setExcessRate("0%");
            }

        });
        Map<String, RegionalOnlineMonitoringVo> numberMonitorsMap = numberMonitors.stream().collect(Collectors.toMap(RegionalOnlineMonitoringVo::getDistrictCode, a -> a,(k1, k2)->k1));
        Map<String, RegionalOnlineMonitoringVo> excessRatesMap = excessRates.stream().collect(Collectors.toMap(RegionalOnlineMonitoringVo::getDistrictCode, a -> a,(k1, k2)->k1));
        regionalOnlineMonitoringVos.forEach(item->{
            if(numberMonitorsMap.containsKey(item.getDistrictCode())){
                item.setNumberMonitoringPoints(numberMonitorsMap.get(item.getDistrictCode()).getNumberMonitoringPoints());
            }else {
                item.setNumberMonitoringPoints("0");
            }
            if(monitoringRatesMap.containsKey(item.getDistrictCode())){
                item.setMonitoringRate(monitoringRatesMap.get(item.getDistrictCode()).getMonitoringRate());
            }else {
                item.setMonitoringRate("0%");
            }
            if(excessRatesMap.containsKey(item.getDistrictCode())){
                item.setExcessRate(excessRatesMap.get(item.getDistrictCode()).getExcessRate());
            }else {
                item.setExcessRate("0%");
            }
        });
        return regionalOnlineMonitoringVos;
    }

    @Override
    public List<RegionalOnlineMonitoringVo> exceedingStandardPoints(EffectiveMonitoringRateQuery query) {
        String regionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> rs = baseRegionService.getRegionCodeListChild(regionCode);
        if(rs.getCode()==200){
            regionCodes=rs.getData();
        }
        query.setRegionCodes(regionCodes);
        List<SysBasRegion> regionArr=new ArrayList<>();
        R<List<SysBasRegion>> r = baseRegionService.getRegionList(regionCode);
        if(r.getCode()==200){
            regionArr=r.getData();
        }
        //封装数据
        List<RegionalOnlineMonitoringVo> regionalOnlineMonitoringVos=new ArrayList<>();
        regionArr.forEach(item->{
            RegionalOnlineMonitoringVo chil=new RegionalOnlineMonitoringVo();
            chil.setRegionName(item.getRegionName());
            chil.setDistrictCode(item.getRegionCode());
            regionalOnlineMonitoringVos.add(chil);
        });
        List<RegionalOnlineMonitoringVo> list= sEnvGasRealMapper.exceedingStandardPoints(query);
        Map<String, RegionalOnlineMonitoringVo> excessRatesMap = list.stream().collect(Collectors.toMap(RegionalOnlineMonitoringVo::getDistrictCode, a -> a,(k1, k2)->k1));
        regionalOnlineMonitoringVos.forEach(item->{
            if(excessRatesMap.containsKey(item.getDistrictCode())){
                item.setTotal(excessRatesMap.get(item.getDistrictCode()).getTotal());
            }else {
                item.setTotal(BigDecimal.valueOf(0));
            }
        });
        regionalOnlineMonitoringVos.sort(Comparator.comparing(RegionalOnlineMonitoringVo::getTotal).reversed());
        return regionalOnlineMonitoringVos;
    }

    @Override
    public List<RegionalOnlineMonitoringVo> exceedingIndustryPoints(EffectiveMonitoringRateQuery query) {
        //WXXYEL
        String regionCode = SecurityUtils.getLoginUser().getSysUser().getRegionCode();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> rs = baseRegionService.getRegionCodeListChild(regionCode);
        if(rs.getCode()==200){
            regionCodes=rs.getData();
        }
        query.setRegionCodes(regionCodes);
        List<RegionalOnlineMonitoringVo> list= sEnvGasRealMapper.exceedingIndustryPoints(query);
        return list;
    }

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

    /**
     * 废气无组织在线监测所有污染物
     */
    public enum PollutantEnum {
        pm10("PM10", "pm10", "μg/m³"),
        pm25("PM2.5", "pm25", "μg/m³"),
        tsp("TSP", "tsp", "μg/m³"),
        nmhc("NMHC", "nmhc", "μg/m³"),
        ch4("甲烷", "ch4", "μg/m³"),
        hydrocarbon("总烃", "hydrocarbon", "μg/m³"),
        benzene("苯", "benzene", "μg/m³"),
        methylbenzene("甲苯", "methylbenzene", "μg/m³"),
        temperature("温度", "temperature", "℃"),
        humidity("湿度", "humidity", "%RH"),
        windDirection("风向", "windDirection", "度"),
        windSpeed("风速", "windSpeed", "m/s"),
        barometricPressure("大气压", "barometricPressure", "hPa");

        public final String label; // 名称
        public final String prop; // 取值属性名
        public final String unit; // 单位

        PollutantEnum(String label, String prop, String unit) {
            this.label = label;
            this.prop = prop;
            this.unit = unit;
        }
        public static PollutantEnum getByProp(String prop) {
            for (PollutantEnum value : values()) {
                if (value.prop.equals(prop)) {
                    return value;
                }
            }
            return null;
        }
    }
}
