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.SStationTypeDict;
import cn.cecep.talroad.domain.TCodStation;
import cn.cecep.talroad.domain.TCodStationDataAir;
import cn.cecep.talroad.domain.TCodStationDataWater;
import cn.cecep.talroad.mapper.SStationTypeDictMapper;
import cn.cecep.talroad.mapper.TCodStationDataAirMapper;
import cn.cecep.talroad.mapper.TCodStationDataWaterMapper;
import cn.cecep.talroad.mapper.TCodStationMapper;
import cn.cecep.talroad.service.ITCodStationService;
import cn.cecep.talroad.vo.EChartsVO;
import cn.cecep.talroad.vo.TCodStationVo;
import cn.cecep.talroad.vo.query.FindSequenceDataQuery;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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


@Service
public class TCodStationServiceImpl extends ServiceImpl<TCodStationMapper, TCodStation> implements ITCodStationService {

    @Autowired
    private TCodStationDataAirMapper stationDataAirMapper;

    @Autowired
    private TCodStationDataWaterMapper stationDataWaterMapper;

    @Autowired
    private SStationTypeDictMapper stationTypeDictMapper;

    /**
     * 大气站点监测参数
     */
    public enum AirPollutantEnum {
        aqi("AQI", "aqi", ""),
        pm25("PM₂.₅", "pm25", "ug/m³"),
        pm10("PM₁₀", "pm10", "ug/m³"),
        so2("SO₂", "so2", "ug/m³"),
        no2("NO₂", "no2", "ug/m³"),
        o3("O₃", "o3", "ug/m³"),
        co("CO", "co", "mg/m³"),
        tvoc("TVOC", "tvoc", "ppb"),
        tsp("TSP", "tsp", "ug/m³"),
        ;

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

        AirPollutantEnum(String label, String prop, String unit) {
            this.label = label;
            this.prop = prop;
            this.unit = unit;
        }

        public static AirPollutantEnum getByProp(String prop) {
            for (AirPollutantEnum value : AirPollutantEnum.values()) {
                if (value.prop.equals(prop)) {
                    return value;
                }
            }
            return null;
        }
    }

    /**
     * 水环境站点监测参数
     */
    public enum WaterPollutantEnum {
        cod("COD", "cod", ""),
        ammoniaNitrogen("氨氮", "ammoniaNitrogen", ""),
        totalNitrogen("总氮", "totalNitrogen", ""),
        totalPhosphorus("总磷", "totalPhosphorus", "");

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

        WaterPollutantEnum(String label, String prop, String unit) {
            this.label = label;
            this.prop = prop;
            this.unit = unit;
        }
    }

    @Override
    public List<TCodStationVo> getStationList(TCodStationVo.SearchVo searchVo) {
        if (searchVo.getStationTypeDictIds() == null || searchVo.getStationTypeDictIds().isEmpty()) {
            return new ArrayList<>();
        }

        // 查询指定类型的字典类型，按照数据源分组
        List<SStationTypeDict> typeList = stationTypeDictMapper.selectBatchIds(searchVo.getStationTypeDictIds());
        Map<String, List<SStationTypeDict>> typeMap = typeList.stream()
                .filter(o -> o.getDataSource() != null)
                .collect(Collectors.groupingBy(SStationTypeDict::getDataSource));

        List<TCodStationVo> result = new ArrayList<>();

        if (typeMap.containsKey("1")) { // 大气
            searchVo.setStationTypeDictIds(typeMap.get("1").stream().map(o -> o.getDataId().intValue()).collect(Collectors.toList()));
            List<TCodStationVo> list = baseMapper.selectAirStationList(searchVo);
            result.addAll(list);
        }
        if (typeMap.containsKey("2")) { // 水
            searchVo.setStationTypeDictIds(typeMap.get("2").stream().map(o -> o.getDataId().intValue()).collect(Collectors.toList()));
            List<TCodStationVo> list = baseMapper.selectWaterStationList(searchVo);
            result.addAll(list);
        }
        return result;
    }

    public EChartsVO getAirChartData(TCodStation station, Date startTime, Date endTime) {
        // x轴数据
        List<String> xdata = DateUtils.getRangeTimes("H", startTime, endTime);

        List<TCodStationDataAir> dataList = stationDataAirMapper.selectList(new QueryWrapper<TCodStationDataAir>()
                .eq("station_id", station.getId())
                .eq("data_type", "H")
                .ge("monitor_time", startTime)
                .le("monitor_time", endTime)
        );
        // 以日期为key,转为map 日期格式要保证与x轴格式一样
        Map<String, TCodStationDataAir> dataMap = dataList.stream()
                .collect(Collectors.toMap(o -> DateUtils.parseDateToStr("yyyy-MM-dd HH", o.getMonitorTime()), o -> o, (o1, o2) -> o1));

        SStationTypeDict stationTypeDict = stationTypeDictMapper.selectById(station.getStationTypeDictId());

        List<AirPollutantEnum> pollutantEnums = Arrays.stream(AirPollutantEnum.values()).collect(Collectors.toList());

        if (StringUtils.isNotEmpty(stationTypeDict.getChartPollutant())) {
            String[] split = stationTypeDict.getChartPollutant().split(",");
            pollutantEnums = Arrays.stream(split).map(AirPollutantEnum::getByProp).filter(Objects::nonNull).collect(Collectors.toList());
        }

        List<EChartsVO.SeriesObj> series = pollutantEnums.stream().map(pollutantEnum -> {
            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 -> {
                TCodStationDataAir dataAir = dataMap.get(o);
                if (dataAir == null) {
                    return null;
                }
                Object property = BeanUtil.getProperty(dataAir, ser.getProp());
                return property != null ? property.toString() : null;
            }).collect(Collectors.toList());
            ser.setValues(values);
            return ser;
        }).collect(Collectors.toList());

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

    public EChartsVO getWaterChartData(String id, Date startTime, Date endTime) {
        // x轴数据
        List<String> xdata = DateUtils.getRangeTimes("H", startTime, endTime);

        List<TCodStationDataWater> dataList = stationDataWaterMapper.selectList(new QueryWrapper<TCodStationDataWater>()
                .eq("station_id", id)
                .eq("data_type", "H")
                .ge("monitor_time", startTime)
                .le("monitor_time", endTime)
        );
        // 以日期为key,转为map 日期格式要保证与x轴格式一样
        Map<String, TCodStationDataWater> dataMap = dataList.stream()
                .collect(Collectors.toMap(o -> DateUtils.parseDateToStr("yyyy-MM-dd HH", o.getMonitorTime()), o -> o, (o1, o2) -> o1));

        List<EChartsVO.SeriesObj> series = Arrays.stream(WaterPollutantEnum.values()).map(pollutantEnum -> {
            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 -> {
                TCodStationDataWater dataWater = dataMap.get(o);
                if (dataWater == null) {
                    return null;
                }
                return BeanUtil.getProperty(dataWater, ser.getProp());
            }).collect(Collectors.toList());
            ser.setValues(values);
            return ser;
        }).collect(Collectors.toList());


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

    @Override
    public TCodStationVo.Air getAirStationDetail(String id) {
        TCodStation station = getById(id);

        TCodStationVo.Air result = new TCodStationVo.Air();
        result.setStationName(station.getStationName());

        TCodStationDataAir realData = stationDataAirMapper.selectReal(id, "H");
        result.setRealData(realData);

        // 当前时间，忽略分钟，秒
        Date now = DateUtils.parseDate(DateUtils.parseDateToStr("yyyy-MM-dd HH", new Date()));

        result.setChartsVO(getAirChartData(station, DateUtils.addDateHours(now, -24), DateUtils.addDateHours(now, -1)));
        return result;
    }

    @Override
    public TCodStationVo.Water getWaterStationDetail(String id) {
        TCodStation station = getById(id);

        TCodStationVo.Water result = new TCodStationVo.Water();
        result.setStationName(station.getStationName());

        TCodStationDataWater realData = stationDataWaterMapper.selectReal(id, "H");
        result.setRealData(realData);

        // 当前时间，忽略分钟，秒
        Date now = DateUtils.parseDate(DateUtils.parseDateToStr("yyyy-MM-dd HH", new Date()));

        result.setChartsVO(getWaterChartData(id, DateUtils.addDateHours(now, -24), DateUtils.addDateHours(now, -1)));
        return result;
    }

    @Override
    public List<Map<String, Object>> findStationPullData() {
        QueryWrapper<SStationTypeDict> sStationTypeDictQuery = new QueryWrapper<>();
        List<Integer> typeCodes = new ArrayList<>();
        typeCodes.add(1);typeCodes.add(2);typeCodes.add(10);
        typeCodes.add(4);
        typeCodes.add(11);
        sStationTypeDictQuery.eq("status",0);
        sStationTypeDictQuery.eq("station_type",1);
        sStationTypeDictQuery.in("type_code",typeCodes);
        sStationTypeDictQuery.orderByAsc("sort");
        List<SStationTypeDict> sStationTypeDicts = stationTypeDictMapper.selectList(sStationTypeDictQuery);
        QueryWrapper<TCodStation> queryWrapper = new QueryWrapper<>();
        List<Map<String, Object>> resultList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(sStationTypeDicts)){
            for (SStationTypeDict sStationTypeDict : sStationTypeDicts) {
                Map<String,Object> map = new HashMap<>();
                map.put("label",sStationTypeDict.getTypeName());
                queryWrapper.clear();
                queryWrapper.eq("station_type_dict_id",sStationTypeDict.getDataId()).orderByAsc("station_name", "id");
                List<TCodStation> tCodStations = baseMapper.selectList(queryWrapper);
                if(CollectionUtil.isNotEmpty(tCodStations)){
                    List<Map<String, Object>> childrenList = new ArrayList<>();
                    for (TCodStation tCodStation : tCodStations) {
                        Map<String,Object> childrenMap = new HashMap<>();
                        childrenMap.put("label",tCodStation.getStationName());
                        childrenMap.put("value",tCodStation.getId());
                        childrenList.add(childrenMap);
                    }
                    map.put("children",childrenList);
                }
                resultList.add(map);
            }
        }
        return resultList;
    }

    @Override
    public Map<String, Object> findSequenceData(FindSequenceDataQuery findSequenceDataQuery) {
        Map<String,Object> resultMap = new HashMap<>();
        String startTime = findSequenceDataQuery.getStartTime();
        String endTime = findSequenceDataQuery.getEndTime();
        String stationId = findSequenceDataQuery.getStationId();
        List<String> stationIds = null;
        if(StringUtils.isNotEmpty(stationId)){
            stationIds = Arrays.asList(stationId.split(","));
        }
        //放入时间列表
        List<String> timeList = DateUtils.getRangeTimes("H", startTime, endTime);
        resultMap.put("timeList",timeList);

        //放入站点列表
        List<TCodStation> data = new ArrayList<>();
        List<String> pointNameList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(stationIds)){
            QueryWrapper<TCodStation> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("id",stationIds);
            queryWrapper.orderByAsc("station_name", "id");
            List<TCodStation> tCodStations = baseMapper.selectList(queryWrapper);
            for (TCodStation tCodStation : tCodStations) {
                pointNameList.add(tCodStation.getStationName());
                data.add(tCodStation);
            }
        }
        resultMap.put("pointName",pointNameList);

        //
        List<Map<String,Object>> dataList = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(data)){
            QueryWrapper<TCodStationDataAir> tCodStationDataAirWrapper = new QueryWrapper<>();
            tCodStationDataAirWrapper.eq("data_type","H");
            tCodStationDataAirWrapper.ge("monitor_time", DateUtil.parse(startTime, "yyyy-MM-dd HH"));
            tCodStationDataAirWrapper.le("monitor_time", DateUtil.parse(endTime, "yyyy-MM-dd HH"));
            tCodStationDataAirWrapper.in("station_id", data.stream().map(TCodStation::getId).collect(Collectors.toList()));

            List<TCodStationDataAir> tCodStationDataAirs = stationDataAirMapper.selectList(tCodStationDataAirWrapper);

            // 以站点和时间为key，转为map，日期格式要与x轴一致
            Map<String, TCodStationDataAir> stationDataAirMap = tCodStationDataAirs.stream().collect(
                    Collectors.toMap(o -> o.getStationId() + "_" + DateUtils.parseDateToStr("yyyy-MM-dd HH", o.getMonitorTime()), o -> o,
                    // 若有重复数据取第一条
                    (o1, o2) -> o1)
            );
            for (TCodStation tCodStation : data) {
                // 遍历时间轴，保证系列值与日期轴一一对应
                List<String> coList = timeList.stream().map(time -> {
                    TCodStationDataAir dataAir = stationDataAirMap.get(tCodStation.getId() + "_" + time);
                    if (dataAir == null) {
                        return null;
                    }
                    return dataAir.getCo() != null ? dataAir.getCo().toString() : null;
                }).collect(Collectors.toList());

                Map<String,Object> dataMap = new HashMap<>();
                dataMap.put("pointName",tCodStation.getStationName());
                dataMap.put("dataList",coList);
                dataList.add(dataMap);
            }
        }
        resultMap.put("dataList",dataList);
        return resultMap;
    }

    @Override
    public List<Map<String, Object>> stationRank(String factorName, String monitorTime) {
        if (factorName == null) {
            return new ArrayList<>();
        }
        if (!Arrays.asList("aqi", "pm25", "pm10", "o3", "so2", "no2", "co").contains(factorName)) {
            return new ArrayList<>();
        }
        if (StringUtils.isEmpty(monitorTime)) {
            // 获取上一个小时
            monitorTime = DateUtils.parseDateToStr("yyyy-MM-dd HH:00:00", DateUtils.addHours(new Date(), -1));
        }
        List<Map<String, Object>> rankList = baseMapper.selectStationRank(factorName, monitorTime);
        return rankList;
    }
}
