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.feign.BaseRegionService;
import cn.cecep.talroad.mapper.*;
import cn.cecep.talroad.service.HomePageMapService;
import cn.cecep.talroad.service.KeyEmittingIndustryService;
import cn.cecep.talroad.vo.*;
import cn.cecep.talroad.vo.homepage.HpmCompanyOverviewVo;
import cn.cecep.talroad.vo.homepage.HpmEnvironmentOverviewVo;
import cn.cecep.talroad.vo.homepage.HpmMeriRatingOverviewVo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

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

/**
 * @author changyw
 * @date 2023/2/22
 */
@Service
public class KeyEmittingIndustryServiceImpl implements KeyEmittingIndustryService {

    @Autowired
    private HomePageMapService homePageMapService;

    @Autowired
    private PcFactoryMapper pcFactoryMapper;

    @Autowired
    private BMainHazardousWasteOutputMapper wasteOutputMapper;

    @Autowired
    private BMainMobileEnforcementMapper mobileEnforcementMapper;

    @Autowired
    private SEnvGasMonRealMapper sEnvGasMonRealMapper;

    @Autowired
    private SEnvWaterMonRealMapper sEnvWaterMonRealMapper;

    @Autowired
    private BMainHazardousWasteOutputMapper hazardousWasteOutputMapper;

    @Autowired
    private STaskYieldTrendMapper sTaskYieldTrendMapper;

    @Autowired
    @Qualifier("baseRegionService")
    private BaseRegionService baseRegionService;

    @Override
    @Cacheable(cacheNames = "IndustryCompanyOverview", key = "(#industry ?: 'ALL')+(#regionCode ?:'ALL')", sync = true)
    public IndustryCompanyOverviewVo selectIndustryCompanyOverview(String industry, String regionCode) {
        IndustryCompanyOverviewVo industryCompanyOverviewVo = new IndustryCompanyOverviewVo();
        HpmCompanyOverviewVo selectCompanyOverview = homePageMapService.selectCompanyOverview(industry,regionCode);

        industryCompanyOverviewVo.setOverviewPollutingUnits(selectCompanyOverview.getOverviewPollutingUnits());
        industryCompanyOverviewVo.setOverviewPollutingEmphasis(selectCompanyOverview.getOverviewPollutingEmphasis());
        industryCompanyOverviewVo.setOverviewUltraLowEmissionsUnit("");

        industryCompanyOverviewVo.setOverviewKeyManagement(selectCompanyOverview.getOverviewKeyManagement());
        industryCompanyOverviewVo.setOverviewSimplifyManagement(selectCompanyOverview.getOverviewSimplifyManagement());
        industryCompanyOverviewVo.setOverviewRegisterManagement(selectCompanyOverview.getOverviewRegisterManagement());

        industryCompanyOverviewVo.setWaterMainOutlet(selectCompanyOverview.getWaterMainOutlet());
        industryCompanyOverviewVo.setWaterAutoOutlet("");
        industryCompanyOverviewVo.setAirMainOutlet(selectCompanyOverview.getAirMainOutlet());
        industryCompanyOverviewVo.setAirAutoOutlet("");
        return industryCompanyOverviewVo;
    }


    public HpmMeriRatingOverviewVo selectMeritRatingOverview(String industry,String regionCode) {
        return homePageMapService.selectMeritRatingOverview(industry,regionCode);
    }


    public HpmEnvironmentOverviewVo selectOnvironmentOverview(String industry,String regionCode) {
        return homePageMapService.selectOnvironmentOverview(industry,regionCode);
    }

    @Override
    @Cacheable(cacheNames = "IndustryEmissionTrackingOverview", key = "((#industry + ':' + #emissionType) ?: 'ALL')+(#regionCode ?:'ALL')", sync = true)
    public List<IndustryEmissionTrackingOverviewVo> selectIndustryEmissionTrackingOverviewVo(String emissionType, String industry, String regionCode) {
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }

        String dataSource = StringUtils.equals(emissionType, "1") ? "执行报告" : "系统核算";

        // 按行业分组，统计大气监测物的排放量、排名等
        List<BMainEmissionPollutionAirVo.IndustryRank> airIndustryRanks = pcFactoryMapper.selectAirEmissionIndustryRank(dataSource, regionCodes);

        // 按行业分组，统计水的监测物的排放量、排名等
        List<BMainEmissionPollutionWaterVo.IndustryRank> waterIndustryRanks = pcFactoryMapper.selectWaterEmissionIndustryRank(dataSource, regionCodes);

        List<IndustryEmissionTrackingOverviewVo> industryEmissionTrackingOverviewVos = new ArrayList<>();

        BMainEmissionPollutionAirVo.IndustryRank airRank = airIndustryRanks.stream()
                .filter(o -> o.getIndustryCategory().equals(industry)).findFirst().orElse(null);
        if (airRank == null) {
            airRank = new BMainEmissionPollutionAirVo.IndustryRank();
        }
        IndustryEmissionTrackingOverviewVo so2 = new IndustryEmissionTrackingOverviewVo();
        so2.setPollName("SO₂");
        so2.setEmissionsActual(airRank.getSo2Actually());
        so2.setEmissionsPermit(airRank.getSo2Allowable());
        so2.setCalculate(airRank.getSo2Ratio());
        so2.setEmissionsActualRatio(airRank.getSo2Ratio());
        so2.setRank(airRank.getSo2Rank());

        IndustryEmissionTrackingOverviewVo pm = new IndustryEmissionTrackingOverviewVo();
        pm.setPollName("颗粒物");
        pm.setEmissionsActual(airRank.getPmActually());
        pm.setEmissionsPermit(airRank.getPmAllowable());
        pm.setCalculate(airRank.getPmRatio());
        pm.setEmissionsActualRatio(airRank.getPmRatio());
        pm.setRank(airRank.getPmRank());

        IndustryEmissionTrackingOverviewVo vocs = new IndustryEmissionTrackingOverviewVo();
        vocs.setPollName("VOCs");
        vocs.setEmissionsActual(airRank.getVocsActually());
        vocs.setEmissionsPermit(airRank.getVocsAllowable());
        vocs.setCalculate(airRank.getVocsRatio());
        vocs.setEmissionsActualRatio(airRank.getVocsRatio());
        vocs.setRank(airRank.getVocsRank());

        IndustryEmissionTrackingOverviewVo nox = new IndustryEmissionTrackingOverviewVo();
        nox.setPollName("NOₓ");
        nox.setEmissionsActual(airRank.getNoxActually());
        nox.setEmissionsPermit(airRank.getNoxAllowable());
        nox.setCalculate(airRank.getNoxRatio());
        nox.setEmissionsActualRatio(airRank.getNoxRatio());
        nox.setRank(airRank.getNoxRank());

        industryEmissionTrackingOverviewVos.add(so2);
        industryEmissionTrackingOverviewVos.add(pm);
        industryEmissionTrackingOverviewVos.add(vocs);
        industryEmissionTrackingOverviewVos.add(nox);


        BMainEmissionPollutionWaterVo.IndustryRank waterRank = waterIndustryRanks.stream()
                .filter(o -> o.getIndustryCategory().equals(industry)).findFirst().orElse(null);
        if (waterRank == null) {
            waterRank = new BMainEmissionPollutionWaterVo.IndustryRank();
        }
        IndustryEmissionTrackingOverviewVo cod = new IndustryEmissionTrackingOverviewVo();
        cod.setPollName("COD");
        cod.setEmissionsActual(waterRank.getCodActually());
        cod.setEmissionsPermit(waterRank.getCodAllowable());
        cod.setCalculate(waterRank.getCodRatio());
        cod.setEmissionsActualRatio(waterRank.getCodRatio());
        cod.setRank(waterRank.getCodRank());

        IndustryEmissionTrackingOverviewVo nhh = new IndustryEmissionTrackingOverviewVo();
        nhh.setPollName("总氮");
        nhh.setEmissionsActual(waterRank.getNhhActually());
        nhh.setEmissionsPermit(waterRank.getNhhAllowable());
        nhh.setCalculate(waterRank.getNhhRatio());
        nhh.setEmissionsActualRatio(waterRank.getNhhRatio());
        nhh.setRank(waterRank.getNhhRank());

        IndustryEmissionTrackingOverviewVo tp = new IndustryEmissionTrackingOverviewVo();
        tp.setPollName("总磷");
        tp.setEmissionsActual(waterRank.getTpActually());
        tp.setEmissionsPermit(waterRank.getTpAllowable());
        tp.setCalculate(waterRank.getTpRatio());
        tp.setEmissionsActualRatio(waterRank.getTpRatio());
        tp.setRank(waterRank.getTpRank());

        IndustryEmissionTrackingOverviewVo tn = new IndustryEmissionTrackingOverviewVo();
        tn.setPollName("氨氮");
        tn.setEmissionsActual(waterRank.getTnActually());
        tn.setEmissionsPermit(waterRank.getTnAllowable());
        tn.setCalculate(waterRank.getTnRatio());
        tn.setEmissionsActualRatio(waterRank.getTnRatio());
        tn.setRank(waterRank.getTnRank());

        industryEmissionTrackingOverviewVos.add(cod);
        industryEmissionTrackingOverviewVos.add(nhh);
        industryEmissionTrackingOverviewVos.add(tp);
        industryEmissionTrackingOverviewVos.add(tn);

        industryEmissionTrackingOverviewVos.parallelStream()
                .forEach(industryEmissionTrackingOverviewVo -> {
                    String pollName = industryEmissionTrackingOverviewVo.getPollName();
                    DistributionOfMajorEmittersVo majorEmittersVo = homePageMapService.selectRankingStat(pollName,regionCode);
                    List<Map<String, Object>> industryEmissionsCount = majorEmittersVo.getIndustryEmissionsCount();

                    String num = industryEmissionsCount.stream()
                            .filter(x -> StringUtils.equals(String.valueOf(x.get("code")), industry))
                            .findFirst()
                            .orElse(new HashMap<>())
                            .getOrDefault("num", 0)
                            .toString();
                    industryEmissionTrackingOverviewVo.setMajorEmittersInTheIndustryNumber(Integer.parseInt(num));
                });
        return industryEmissionTrackingOverviewVos;
    }

    @Override
    public List<IndustrialHazardousWasteVo> selectProductionAndDisposalOfIndustrialHazardousWaste(String industry, String regionCode) {
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }
        List<IndustrialHazardousWasteVo> hazardousWasteVos = wasteOutputMapper.selectTop5WasteByIndustry(industry,regionCodes);

        for (IndustrialHazardousWasteVo hazardousWasteVo : hazardousWasteVos) {
            DistributionOfMajorEmittersVo distributionOfMajorEmittersVo = homePageMapService.selectRankingStat(hazardousWasteVo.getMaterialsCode(), regionCode);
            List<Map<String, Object>> industryEmissionsCount = distributionOfMajorEmittersVo.getIndustryEmissionsCount();
            if(industryEmissionsCount!=null) {
                String num = industryEmissionsCount.stream()
                        .filter(x -> StringUtils.equals(String.valueOf(x.get("code")), industry))
                        .findFirst()
                        .orElse(new HashMap<>())
                        .getOrDefault("num", 0)
                        .toString();
                hazardousWasteVo.setMajorEmittersInTheIndustryNumber(num);
            }
        }

        return hazardousWasteVos;
    }

    @Override
    @Cacheable(cacheNames = "IndustryPollutantDischargeTrends", key = "((#industry + ':' + #pollutantCategory) ?: 'ALL')+(#regionCode ?:'ALL')", sync = true)
    public EChartsVO selectIndustryPollutantDischargeTrends(String pollutantCategory, String industry, String regionCode) {
        EChartsVO eChartsVO = new EChartsVO();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }
        DateTime nowDateTime = new DateTime();
        DateTime monitoringStartTime = DateUtil.offsetMonth(nowDateTime, -11);
        List<String> dateMonthList = CollUtil.map(DateUtil.rangeToList(monitoringStartTime, nowDateTime, DateField.MONTH), x -> DateUtil.format(x,"yyyy-MM"), true);
        eChartsVO.setXData(dateMonthList);

        switch (pollutantCategory) {
            case "0":
                List<Map<String, String>> items = new ArrayList<>();
                items.add(new HashMap<String, String>() {{
                    put("name", "二氧化硫");
                    put("prop", "so2Emission");
                    put("unit", "kg");
                }});
                items.add(new HashMap<String, String>() {{
                    put("name", "氮氧化物");
                    put("prop", "noxEmission");
                    put("unit", "kg");
                }});
                items.add(new HashMap<String, String>() {{
                    put("name", "颗粒物");
                    put("prop", "pmEmission");
                    put("unit", "kg");
                }});
                items.add(new HashMap<String, String>() {{
                    put("name", "VOCs");
                    put("prop", "vocsEmission");
                    put("unit", "kg");
                }});

                List<SEnvGasMonRealVo> sEnvGasMonRealVos = sEnvGasMonRealMapper.selectSEnvGasMonRealListGroupByYear(monitoringStartTime.toString(), nowDateTime.toString(), industry,regionCodes);

                List<EChartsVO.SeriesObj> series = items.stream().map(item -> {
                    EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                    ser.setName(item.get("name"));
                    ser.setUnit(item.get("unit") == null ? "" : item.get("unit"));
                    List<Object> values = sEnvGasMonRealVos.stream().map(o -> BeanUtil.getProperty(o, item.get("prop"))).collect(Collectors.toList());
                    ser.setValues(values);
                    return ser;
                }).collect(Collectors.toList());
                eChartsVO.setSeries(series);
                break;
            case "1":
                items = new ArrayList<>();
                items.add(new HashMap<String, String>() {{
                    put("name", "化学需氧量");
                    put("prop", "codEmission");
                    put("unit", "kg");
                }});
                items.add(new HashMap<String, String>() {{
                    put("name", "氨氮");
                    put("prop", "ammoniaNitrogenEmission");
                    put("unit", "kg");
                }});
                items.add(new HashMap<String, String>() {{
                    put("name", "总氮");
                    put("prop", "nitrogenConcentrationEmission");
                    put("unit", "kg");
                }});
                items.add(new HashMap<String, String>() {{
                    put("name", "总磷");
                    put("prop", "phosphorusConcentrationEmission");
                    put("unit", "kg");
                }});

                List<SEnvWaterMonRealVo> sEnvWaterMonRealVos = sEnvWaterMonRealMapper.selectSEnvWaterMonRealListGroupByYear(monitoringStartTime.toString(), nowDateTime.toString(), industry,regionCodes);

                series = items.stream().map(item -> {
                    EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                    ser.setName(item.get("name"));
                    ser.setUnit(item.get("unit") == null ? "" : item.get("unit"));
                    List<Object> values = sEnvWaterMonRealVos.stream().map(o -> BeanUtil.getProperty(o, item.get("prop"))).collect(Collectors.toList());
                    ser.setValues(values);
                    return ser;
                }).collect(Collectors.toList());

                eChartsVO.setSeries(series);

                break;
            case "2":
                List<IndustrialHazardousWasteVo> industrialHazardousWasteVos = hazardousWasteOutputMapper.selectWasteListGroupByIndustry(monitoringStartTime.year() + "", nowDateTime.year() + "", monitoringStartTime.month() + "", nowDateTime.month() + "", industry,regionCodes);

                series = industrialHazardousWasteVos.stream()
                        .map(IndustrialHazardousWasteVo::getMaterialsName)
                        .distinct()
                        .map(materialsName -> {
                            EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                            ser.setName(materialsName);
                            ser.setUnit("吨");

                            float[] values = new float[dateMonthList.size()];

                            industrialHazardousWasteVos.stream().filter(o -> StringUtils.equals(o.getMaterialsName(), materialsName))
                                    .forEach(o -> {
                                        int i = dateMonthList.indexOf(o.getParticularYear() + "-" + (o.getParticularMonth().length() == 2 ? o.getParticularMonth() : ("0" + o.getParticularMonth())));
                                        if (i >= 0) {
                                            values[i] = Float.parseFloat(o.getMaterialsUse());
                                        }
                                    });

                            ser.setValues(Arrays.asList(values));
                            return ser;
                        })
                        .collect(Collectors.toList());
                eChartsVO.setSeries(series);
                break;
            default:
                break;
        }
        return eChartsVO;
    }

    @Override
    @Cacheable(cacheNames = "IndustryProductOutputTrends", key = "(#industry ?: 'ALL')+(#regionCode ?:'ALL')", sync = true)
    public EChartsVO selectIndustryProductOutputTrends(String industry, String regionCode) {
        EChartsVO eChartsVO = new EChartsVO();
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }
        DateTime nowDateTime = new DateTime();
        DateTime monitoringStartTime = DateUtil.offsetMonth(nowDateTime, -11);
        String dateFormat = "yyyy-MM";
        List<String> dateMonthList = CollUtil.map(DateUtil.rangeToList(monitoringStartTime, nowDateTime, DateField.MONTH), x -> DateUtil.format(x, dateFormat), true);
        eChartsVO.setXData(dateMonthList);

        List<STaskYieldTrendVo> sTaskYieldTrends = sTaskYieldTrendMapper.selectMonthListGroupByIndustry(industry, DateUtils.parseFormatDate(dateFormat, monitoringStartTime), DateUtils.parseFormatDate(dateFormat,nowDateTime),regionCodes);

        Map<String, List<STaskYieldTrendVo>> collect1 = sTaskYieldTrends.stream()
                .collect(Collectors.groupingBy(STaskYieldTrendVo::getDictCode,
                        Collectors.collectingAndThen(Collectors.toList(),
                                a -> a.stream().sorted(Comparator.comparing(STaskYieldTrendVo::getDataTime)).collect(Collectors.toList()))));

        List<EChartsVO.SeriesObj> collect = collect1.entrySet().stream()
                .map(entry -> {
                    EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
                    ser.setName(CollUtil.getFirst(entry.getValue().iterator()).getSmall());
                    ser.setUnit(CollUtil.getFirst(entry.getValue().iterator()).getUnit());

                    List<Object> values = dateMonthList.stream()
                            .map(dataTime -> CollUtil.findOneByField(entry.getValue(), "dataTime", dataTime))
                            .map(x -> Objects.isNull(x) ? null : x.getNumber().setScale(4, RoundingMode.HALF_UP))
                            .collect(Collectors.toList());
                    ser.setValues(values);
                    return ser;
                })
                .collect(Collectors.toList());

        eChartsVO.setSeries(collect);
        return eChartsVO;
    }

    @Override
    @Cacheable(cacheNames = "Top10CompaniesWithPollutantEmissionsInTheIndustry", key = "((#industry + ':' + #pollutantType) ?: 'ALL')+(#regionCode?:'ALL')", sync = true)
    public List<IndustryPollutantEmissionsTop10Vo> selectTop10CompaniesWithPollutantEmissionsInTheIndustry(String pollutantType, String industry, String regionCode) {
        List<String> regionCodes=new ArrayList<>();
        R<List<String>> r = baseRegionService.getRegionCodeListChild(regionCode);
        if(r.getCode()==200){
            regionCodes=r.getData();
        }
        List<IndustryPollutantEmissionsTop10Vo> emissionsTop10Vos = pcFactoryMapper.selectTop10CompaniesWithPollutantEmissionsInTheIndustry(industry, pollutantType,regionCodes);

        BigDecimal max = emissionsTop10Vos.stream().map(IndustryPollutantEmissionsTop10Vo::getEmissions).reduce(BigDecimal.ZERO, BigDecimal::max);
        if (max.compareTo(BigDecimal.ZERO) != 0) {
            BigDecimal emissions95 = max.multiply(BigDecimal.valueOf(0.95)).setScale(4, RoundingMode.HALF_UP);
            emissionsTop10Vos
                    .forEach(x -> {
                        BigDecimal emissions = x.getEmissions();
                        if (emissions.compareTo(emissions95) >= 0) {
                            x.setIsBigEmitter(1);
                        }
                    });
        }

        return emissionsTop10Vos;
    }

    @Override
    public EChartsVO selectLawEnforcementStatistics(String industry) {
        EChartsVO eChartsVO = new EChartsVO();
        List<String> dateMonthList = CollUtil.map(DateUtil.rangeToList(DateUtil.offsetMonth(new Date(), -5), new DateTime(), DateField.MONTH), x -> DateUtil.format(x,"yyyy-MM"), true);
        eChartsVO.setXData(dateMonthList);

        List<String> items = Lists.newArrayList("双随机", "企业核查", "无问题", "立行立改", "拟立案处罚");

        List<HashMap<String, Object>> searchResult = mobileEnforcementMapper.selectLawEnforcementStatistics(industry);
        Map<String, List<HashMap<String, Object>>> searchGroup = searchResult.stream()
                .collect(Collectors.groupingBy(x -> x.get("monthrange").toString()));

        HashMap<String, Object> defaultValueMap = Maps.newHashMap();
        defaultValueMap.put("count", 0);

        List<EChartsVO.SeriesObj> collect = items.stream().map(item -> {
            EChartsVO.SeriesObj ser = new EChartsVO.SeriesObj();
            ser.setName(item);
            List<Object> values = dateMonthList.stream().map(dateMonth -> {
                List<HashMap<String, Object>> hashMaps = searchGroup.getOrDefault(dateMonth, Lists.newArrayList());
                Optional<HashMap<String, Object>> first = hashMaps.stream().filter(hashMap -> hashMap.get("tasktype").equals(item)).findFirst();

                return first.orElse(defaultValueMap).get("count");
            }).collect(Collectors.toList());
            ser.setValues(values);
            return ser;
        }).collect(Collectors.toList());

        eChartsVO.setSeries(collect);
        eChartsVO.setName("执法情况统计");
        return eChartsVO;
    }

    @Override
    public EChartsVO selectIndustryPollutantTreatmentProcess(String industry) {
        return new EChartsVO();
    }

    @Override
    public List<LawEnforcementPieStatisticsVo> selectLawEnforcementPieStatistics(Map map) {
        List<LawEnforcementPieStatisticsVo> data = mobileEnforcementMapper.selectLawEnforcementPieStatistics(map);
        return data;
    }

}
