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

import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.common.core.utils.bean.BeanUtils;
import cn.cecep.talroad.common.security.utils.SecurityUtils;
import cn.cecep.talroad.domain.effective.PcNationalCityRankingHour;
import cn.cecep.talroad.domain.effective.PcNationalCityRankingOther;
import cn.cecep.talroad.domain.effective.PcNationalCountyRankingHour;
import cn.cecep.talroad.domain.effective.PcNationalCountyRankingOther;
import cn.cecep.talroad.mapper.effective.*;
import cn.cecep.talroad.service.effective.ReductionEmissionService;
import cn.cecep.talroad.vo.EChartsVO;
import cn.cecep.talroad.vo.effective.PcNationalCityRanking;
import cn.cecep.talroad.vo.effective.PcNationalCountyRanking;
import cn.cecep.talroad.vo.export.PcNationalCityRankingExport;
import cn.cecep.talroad.vo.export.PcNationalCountyRankingExport;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.cecep.talroad.common.core.utils.DateUtils.YYYY_MM_DD_HH_MM_SS;

@AllArgsConstructor
@Service
public class ReductionEmissionServiceImpl implements ReductionEmissionService {
    private ReductionEmissionMapper mapper;
    private PcNationalCityRankingHourMapper hourMapper;
    private PcNationalCountyRankingHourMapper countyhourMapper;
    private PcNationalCountyRankingOtherMapper countyotherMapper;
    private PcNationalCityRankingOtherMapper otherMapper;

    @Override
    public PcNationalCityRanking realTimeMonitoringService(String regionCode) {
        PcNationalCityRanking pcNationalCityRanking = mapper.realTimeMonitoring(regionCode);
        return pcNationalCityRanking;
    }

    @Override
    public Map<String, Object> cityRankingService(String regionCode) {
        List<PcNationalCityRanking> pcNationalCityRankings = mapper.cityRanking(regionCode);
        Map<String, Object> map = new HashMap<>(4);
        Map<String, Object> map168 = new HashMap<>();
        Map<String, Object> map337 = new HashMap<>();
        Map<String, Object> mapProvinceCity = new HashMap<>();
        pcNationalCityRankings.stream().forEach(r -> {
            map168.put(r.getDateType().trim(), r.getIndex168());
            map337.put(r.getDateType().trim(), r.getIndex337());
            mapProvinceCity.put(r.getDateType().trim(), r.getIndexProvinceCity());
        });
        map.put("168", map168);
        map.put("337", map337);
        map.put("province_city", mapProvinceCity);
        return map;
    }

    /**
     * @Method countyRankingService
     * @Exception 省区县
     * @Date 2023/6/16 17:03
     */
    @Override
    public Map<String, Object> countyRankingService(String regionCode) {
        List<PcNationalCountyRankingOther> pcNationalCountyRankingOthers = mapper.countyRanking(regionCode);
        Map<String, Object> map = new HashMap<>(4);
        Map<String, Object> mapProvinceCounty = new HashMap<>();
        pcNationalCountyRankingOthers.forEach(r -> {
            mapProvinceCounty.put(r.getDateType().trim(), r.getIndex());
        });
        map.put("province_county", mapProvinceCounty);
        return map;
    }

    @Override
    public IPage<PcNationalCityRanking> list(String dateType, String type, String date, Integer pageNum, Integer pageSize,String cityName) {
        Pattern pattern = Pattern.compile("^[0-9]+$");
        IPage<PcNationalCityRanking> pcNationalCityRankings = new Page<>();
        QueryWrapper query = new QueryWrapper();
        String sql="id,pcode,pname,\"cityName\",\"cityId\",aqi,\"maxPollution\",pm25,\n" +
                "pm10,o3,so2,no2,co,date_time,index_337,is_337,is_168,index_168,index_province_city,index_province_county";

        if (pattern.matcher(type).matches()) {
            query.isNotNull("is_" + type);
            query.eq("is_" + type, "1");

        }else {
            //查询省内城市排名
            int i = Integer.parseInt(SecurityUtils.getLoginUser().getSysUser().getRegionCode().substring(0, 2));
            query.between("\"cityId\"",i*10000,(i+1)*10000 );
        }
        if (ObjectUtils.isNotEmpty(date)) {
            query.likeRight("cast(date_time as varchar) ", date);
        }
        if (ObjectUtils.isNotEmpty(type)) {
            query.orderByAsc("index_" + type +" :: NUMERIC");
            sql= sql+",index_" + type+" AS index";
        }
        query.select(sql).lambda();
        query.like(StringUtils.isNotBlank(cityName),"\"cityName\"", cityName);
        if ("H".equals(dateType)) {
            Page<PcNationalCityRankingHour> p = new Page<>(pageNum, pageSize);
            IPage<PcNationalCityRankingHour> pcNationalCityRankingHours = hourMapper.selectPage(p, query);
            BeanUtils.copyBeanProp(pcNationalCityRankings, pcNationalCityRankingHours);
        } else {
            query.eq("date_type", dateType);
            Page<PcNationalCityRankingOther> p = new Page<>(pageNum, pageSize);
            IPage<PcNationalCityRankingOther> pcNationalCityRankingSqls = otherMapper.selectPage(p, query);
            BeanUtils.copyBeanProp(pcNationalCityRankings, pcNationalCityRankingSqls);
        }

        return pcNationalCityRankings;

    }


    /**
     * @Method list
     * @Author wyg
     * @Version 1.0
     * @Description * @param null
     * @Return 省区县排名
     * @Exception
     * @Date 2023/6/16 18:00
     */
    @Override
    public IPage<PcNationalCountyRanking> provinceCounty(String dateType, String type, String date,
                                                         Integer pageNum, Integer pageSize,String countyName) {
        IPage<PcNationalCountyRanking> PcNationalCountyRanking = new Page<>();
        QueryWrapper query = new QueryWrapper();
        query.select("id,city_code,city_name,\"country_code\",\"country_name\",all_name,aqi,\"maxPollution\",pm25,\n" +
                "pm10,o3,so2,no2,co,date_time,index ").lambda();
        if (ObjectUtils.isNotEmpty(date)) {
            query.likeRight("cast(date_time as varchar) ", date);
        }
        query.orderByAsc("date_time");
        query.orderByAsc("index :: NUMERIC");
        query.like(StringUtils.isNotBlank(countyName),"all_name", countyName);
        if ("H".equals(dateType)) {
            Page<PcNationalCountyRankingHour> p = new Page<>(pageNum, pageSize);
            IPage<PcNationalCountyRankingHour> pcNationalCountyRankingHours = countyhourMapper.selectPage(p, query);
            BeanUtils.copyBeanProp(PcNationalCountyRanking, pcNationalCountyRankingHours);
        } else {
            query.eq("date_type", dateType);
            Page<PcNationalCountyRankingOther> p = new Page<>(pageNum, pageSize);
            IPage<PcNationalCountyRankingOther> pcNationalCountyRankingSqls = countyotherMapper.selectPage(p, query);
            BeanUtils.copyBeanProp(PcNationalCountyRanking, pcNationalCountyRankingSqls);
        }
        return PcNationalCountyRanking;

    }


    @Override
    public Map<String, Object> getMapService(String type) {
        long l = System.currentTimeMillis() / 1000;
        LocalDate today = LocalDate.now();
        LocalDate startDate = LocalDate.of(today.getYear(), 1, 1);
        List<String> dateList = CollUtil.map(DateUtil.rangeToList(Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                        Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()), DateField.DAY_OF_MONTH),
                x -> DateUtil.format(x, "yyyy-MM-dd"), true);
        QueryWrapper<PcNationalCityRankingOther> query = Wrappers.query();
        query.ge(PcNationalCityRankingOther.COL_DATE_TIME, startDate);
        query.le(PcNationalCityRankingOther.COL_DATE_TIME, today);
        query.ge(PcNationalCityRankingOther.COL_DATE_TYPE, "D");
        query.eq("\"cityId\"", Integer.parseInt(SecurityUtils.getLoginUser().getSysUser().getRegionCode()));
        query.select("index_" + type + " AS aqi,date_time ");
        long l1 = System.currentTimeMillis() / 1000;
        List<PcNationalCityRankingOther> pcNationalCityRankingOthers = otherMapper.selectList(query);
        long l3 = System.currentTimeMillis() / 1000;
        List<String> yList = new ArrayList<>();
        for (PcNationalCityRankingOther pcNationalCityRankingOther : pcNationalCityRankingOthers) {
            pcNationalCityRankingOther.setDateTimeFormat(DateUtil.format(pcNationalCityRankingOther.getDateTime(), "yyyy-MM-dd"));
        }
        if (!CollectionUtils.isEmpty(dateList)) {
            for (String s : dateList) {
                if (pcNationalCityRankingOthers.stream().anyMatch(pc -> s.equals(pc.getDateTimeFormat()))) {
                    yList.add(pcNationalCityRankingOthers.stream().filter(pc -> s.equals(pc.getDateTimeFormat())).collect(Collectors.toList()).get(0).getAqi());
                } else {
                    yList.add("0");
                }
            }
        }
        long l4 = System.currentTimeMillis() / 1000;
        System.out.println("查询之前"+(l1-l));
        System.out.println("查询"+(l3-l1));
        System.out.println("查询之后"+(l4-l3));
        Map<String, Object> map = new HashMap<>();
        map.put("xlist", dateList);
        map.put("yList", yList);
        return map;
    }

    /**
     * @Method 省区县多区域查询
     * @Author wyg
     * @Version 1.0
     * @Description * @param null
     * @Return
     * @Exception 省区县
     * @Date 2023/6/16 18:33
     */
    @Override
    public Map<String, Object> getMapCountyService(String[] countryCode) {
        LocalDate today = LocalDate.now();
        LocalDate startDate = LocalDate.of(today.getYear(), 1, 1);
        List<String> dateList = CollUtil.map(DateUtil.rangeToList(Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                        Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()), DateField.DAY_OF_MONTH),
                x -> DateUtil.format(x, "yyyy-MM-dd"), true);
        QueryWrapper<PcNationalCountyRankingOther> query = Wrappers.query();
        query.ge(PcNationalCityRankingOther.COL_DATE_TIME, DateUtils.dateTime(YYYY_MM_DD_HH_MM_SS, startDate + " 00:00:00"));
        query.le(PcNationalCityRankingOther.COL_DATE_TIME, DateUtils.dateTime(YYYY_MM_DD_HH_MM_SS, today + " 23:59:59"));
        query.ge(PcNationalCityRankingOther.COL_DATE_TYPE, "D");
        query.likeRight("all_name", "唐山市");
        query.in("all_name", countryCode);
        query.select("index ,date_time,country_code,country_name ");
        query.orderByAsc("country_code", PcNationalCityRankingOther.COL_DATE_TIME);
        List<Map<String, Object>> listMap = new ArrayList<>();
        List<PcNationalCountyRankingOther> pcNationalCountyRankingOthers = countyotherMapper.selectList(query);
        Map<String, List<PcNationalCountyRankingOther>> glist =
                pcNationalCountyRankingOthers.stream().collect(Collectors.groupingBy(PcNationalCountyRankingOther::getCountryname));
        if (!CollectionUtils.isEmpty(Collections.singleton(glist))) {
            glist.forEach((key, value) -> {
                Map<String, Object> map1 = new HashMap<>();
                map1.put("name", key);
                List<Object> li = new ArrayList<>();
                for (String s : dateList) {
                    Optional<PcNationalCountyRankingOther> first = value.stream().filter(v ->s.equals(DateUtil.format(v.getDateTime(), "yyyy-MM-dd"))).findFirst();
                    if (first.isPresent()) {
                        PcNationalCountyRankingOther pr = first.get();
                        li.add(Integer.valueOf(pr.getIndex()));
                    } else {
                        li.add(0L);
                    }
                }
                map1.put("data", li);
                map1.put("type", "line");
                listMap.add(map1);
            });
        }

        Map<String, Object> map = new HashMap<>();
        map.put("xAxis", dateList);
        map.put("series", listMap);
        return map;
    }


    /**
     * @Method export
     * @Author wyg
     * @Version 1.0
     * @Description * @param null
     * @Return
     * @Exception
     * @Date 2023/6/16 18:05
     */
    @Override
    public List<PcNationalCityRankingExport> export(PcNationalCityRankingExport pcNationalCityRankingExport) {
        QueryWrapper query = new QueryWrapper();
        String sql="id,pcode,pname,\"cityName\",\"cityId\",aqi,\"maxPollution\",pm25,\n" +
                "pm10,o3,so2,no2,co,date_time,is_168,index_168,index_province_city,index_province_county";
        Pattern pattern = Pattern.compile("^[0-9]+$");
        if (pattern.matcher(pcNationalCityRankingExport.getType()).matches()) {
            query.isNotNull("is_" + pcNationalCityRankingExport.getType());
            query.eq("is_" + pcNationalCityRankingExport.getType(), "1");

        }else {
            //查询省内城市排名
            int i = Integer.parseInt(SecurityUtils.getLoginUser().getSysUser().getRegionCode().substring(0, 2));
            query.between("\"cityId\"",i*10000,(i+1)*10000 );
        }
        if (ObjectUtils.isNotEmpty(pcNationalCityRankingExport.getDate())) {
            query.likeRight("cast(date_time as varchar) ", pcNationalCityRankingExport.getDate());
        }
        if (ObjectUtils.isNotEmpty(pcNationalCityRankingExport.getType())) {
            query.orderByAsc("index_" + pcNationalCityRankingExport.getType()+":: NUMERIC");
            sql= sql+",index_" + pcNationalCityRankingExport.getType()+" AS index";
        }
        query.select(sql).lambda();
        if ("H".equals(pcNationalCityRankingExport.getDateType())) {
            List<PcNationalCityRankingHour> list1 = hourMapper.selectList(query);
            return BeanUtil.copyToList(list1, PcNationalCityRankingExport.class);
        } else {
            query.eq("date_type", pcNationalCityRankingExport.getDateType());
            List<PcNationalCityRankingOther> list2 = otherMapper.selectList(query);
            return BeanUtil.copyToList(list2, PcNationalCityRankingExport.class);
        }
    }


    /**
     * @Method export
     * @Author wyg
     * @Version 1.0
     * @Description * @param null
     * @Return 省区县排名导出
     * @Exception
     * @Date 2023/6/16 18:16
     */
    @Override
    public List<PcNationalCountyRankingExport> countyExport(PcNationalCountyRankingExport pcNationalCountyRankingExport) {
        QueryWrapper query = new QueryWrapper();
        query.select("id,city_code,city_name,\"country_code\",\"country_name\",all_name,aqi,\"maxPollution\",pm25,\n" +
                "pm10,o3,so2,no2,co,date_time,index ").lambda();
        if (ObjectUtils.isNotEmpty(pcNationalCountyRankingExport.getDate())) {
            query.likeRight("cast(date_time as varchar) ", pcNationalCountyRankingExport.getDate());
        }
        query.orderByAsc("index"+":: NUMERIC");
        if ("H".equals(pcNationalCountyRankingExport.getDateType())) {
            List<PcNationalCountyRankingHour> list1 = countyhourMapper.selectList(query);
            return BeanUtil.copyToList(list1, PcNationalCountyRankingExport.class);
        } else {
            query.eq("date_type", pcNationalCountyRankingExport.getDateType());
            List<PcNationalCountyRankingOther> list2 = countyotherMapper.selectList(query);
            return BeanUtil.copyToList(list2, PcNationalCountyRankingExport.class);
        }
    }

    @Override
    public EChartsVO getCountryMapService(List<String> names) {
        EChartsVO eChartsVO = new EChartsVO();
        LocalDateTime today = LocalDateTime.now();
        LocalDateTime startDate = today.plus(-1, ChronoUnit.DAYS);
        List<String> dateList = CollUtil.map(DateUtil.rangeToList(Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()),
                        Date.from(today.atZone(ZoneId.systemDefault()).toInstant()), DateField.HOUR),
                x -> DateUtil.format(x, "yyyy-MM-dd HH"), true);
        eChartsVO.setXData(dateList);
        //调用接口查数据
//        List<PcNationalCityRanking> list = mapper.selectByNames(names);
        List<PcNationalCityRanking> list = mapper.selecthourByNames(names,startDate,today);
        list.forEach(d -> {
            Date analyseTime = d.getDateTime();
            String format = DateUtil.format(analyseTime, "yyyy-MM-dd HH");
            d.setDateStr(format);
        });
        Map<String, List<PcNationalCityRanking>> smap = list.stream().collect(Collectors.groupingBy(PcNationalCityRanking::getCityName));
        List<EChartsVO.SeriesObj> seriesObjs = smap.entrySet().stream().map(entry -> {
            EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
            ser.setName(entry.getKey());
            ser.setProp(entry.getKey());
            List<Object> values = new ArrayList<>();
            for (String s : dateList) {
                List<PcNationalCityRanking> value = entry.getValue();
                Optional<PcNationalCityRanking> first = value.stream().filter(v -> v.getDateStr().equals(s)).findFirst();
                if (first.isPresent()) {
                    PcNationalCityRanking pr = first.get();
                    values.add(pr.getIndex());
                } else {
                    values.add(0L);
                }
            }
            ser.setValues(values);
            return ser;
        }).collect(Collectors.toList());

        eChartsVO.setXData(dateList);
        eChartsVO.setSeries(seriesObjs);
        return eChartsVO;
    }

    @Override
    public List<String> countryNameList(String name,String type) {
        QueryWrapper<PcNationalCityRankingOther> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("\"cityName\"");
        queryWrapper.groupBy("\"cityName\"");
        queryWrapper.eq("is_" + type,"1");
        queryWrapper.like(StringUtils.isNotBlank(name),"\"cityName\"", name);
        return otherMapper.selectList(queryWrapper).stream().map(PcNationalCityRankingOther::getCityname).collect(Collectors.toList());
    }

    @Override
    public List<String> cityNameList(String name) {
        QueryWrapper<PcNationalCountyRankingHour> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("all_name");
        queryWrapper.groupBy("all_name");
        queryWrapper.like(StringUtils.isNotBlank(name),"\"all_name\"", name);
//        List<PcNationalCountyRankingOther> pcNationalCountyRankingOthers = countyotherMapper.selectList(queryWrapper);
        List<PcNationalCountyRankingHour> pcNationalCountyRankingOthers = countyhourMapper.selectList(queryWrapper);
        if(pcNationalCountyRankingOthers.size()>0) {
            return pcNationalCountyRankingOthers.stream().filter(Objects::nonNull).map(PcNationalCountyRankingHour::getAllname).collect(Collectors.toList());
        }else {
            return Collections.emptyList();
        }
    }
}
