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

import cn.cecep.talroad.domain.*;
import cn.cecep.talroad.enums.PcLabelCodeEnum;
import cn.cecep.talroad.enums.PcLabelValueCodeEnum;
import cn.cecep.talroad.mapper.AmProblemFiMapper;
import cn.cecep.talroad.mapper.PcOutletMapper;
import cn.cecep.talroad.mapper.SEnvWaterMonDayMapper;
import cn.cecep.talroad.service.*;
import cn.cecep.talroad.service.analysis.IPollWaterAnalysisService;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class PollWaterAnalysisServiceImpl implements IPollWaterAnalysisService {

    @Autowired
    private IBMainEmissionPollutionWaterService mainEmissionPollutionWaterService;
    @Autowired
    private IPcLabelService pcLabelService;
    @Autowired
    private IPcLabelFactoryService pcLabelFactoryService;
    @Autowired
    private SEnvWaterMonDayMapper waterMonDayMapper;
    @Autowired
    private AmProblemFiMapper amProblemFiMapper;
    @Autowired
    private PcOutletMapper outletMapper;
    @Autowired
    private IBMainPollDisWaterMoutService pollDisWaterMoutService;
    @Autowired
    private IBMainPollDisWaterOoutService pollDisWaterOoutService;

    @Override
    public void emissionPollutionWaterLabelTask() {
//        5ac352c3-74a1-418b-b278-148819945e1e  PF021  1年内是否有废水污染物总量超标情况
        //根据 code=PF021 查询 labelId
        PcLabel pcLabel = pcLabelService.lambdaQuery().eq(PcLabel::getLabelCode, PcLabelCodeEnum.PF021.getCode()).one();
        if(pcLabel == null){
            return;
        }
        String labelId  = pcLabel.getId();
        Calendar instance = Calendar.getInstance();
        //前一年
        //instance.add(Calendar.YEAR, -1);
        //本年
        String dataYear = instance.get(Calendar.YEAR) + "";

        BMainEmissionPollutionWater emissionPollutionWater = new BMainEmissionPollutionWater();
        emissionPollutionWater.setPollYear(dataYear);
        List<PcLabelFactory> saveList = new ArrayList<>();
        //根据年份查询数据查询
        List<BMainEmissionPollutionWater> pollutionWaterList = mainEmissionPollutionWaterService.selectBMainEmissionPollutionWaterList(emissionPollutionWater);
        for (BMainEmissionPollutionWater bMainEmissionPollutionWater : pollutionWaterList) {
            String factoryId = bMainEmissionPollutionWater.getFactoryId();

            PcLabelValueCodeEnum pcLabelValueCodeEnum = verifyObj(bMainEmissionPollutionWater);
            if(pcLabelValueCodeEnum != null){
                PcLabelFactory pcLabelFactory = new PcLabelFactory();
                pcLabelFactory.setId(UUID.randomUUID().toString());
                pcLabelFactory.setFactoryId(factoryId);
                pcLabelFactory.setLabelId(labelId);
                pcLabelFactory.setLableUseing("0");
                pcLabelFactory.setLabelValue(pcLabelValueCodeEnum.getCode());//不超总量
                pcLabelFactoryService.lambdaUpdate().eq(PcLabelFactory::getFactoryId,factoryId)
                        .eq(PcLabelFactory::getLabelId,labelId)
                        .remove();
                saveList.add(pcLabelFactory);
            }
        }
        pcLabelFactoryService.saveBatch(saveList);
    }
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public void envWaterMonDayLabelTask() {
//        3e812063-b836-4d93-b6b3-40f6955df9f9  PF020  1年内是否有废水污染物排放浓度情况
        //根据 code=PF021 查询 labelId
        PcLabel pcLabel = pcLabelService.lambdaQuery().eq(PcLabel::getLabelCode, PcLabelCodeEnum.PF020.getCode()).one();
        if(pcLabel == null){
            return;
        }
        String labelId  = pcLabel.getId();
        LocalDate now = LocalDate.now();
        //前一月
        LocalDate preMonth = now.plusMonths(-1);
        //前一月的第一天
        LocalDateTime firstDay = LocalDateTime.of(preMonth.withDayOfMonth(1), LocalTime.MIN);
        //前一月的最后一天
        LocalDateTime lastDay = LocalDateTime.of(preMonth.with(TemporalAdjusters.lastDayOfMonth()),LocalTime.MAX);
        //前一月 所有废水排污预警数据
        List<AmProblemFi> amProblemFis = amProblemFiMapper.selectPollutionWaterData(firstDay, lastDay);
        //前一月 排污口日数据  最大值
        List<SEnvWaterMonDay> sEnvWaterMonDays = waterMonDayMapper.selectMaxByDate(firstDay.format(formatter), lastDay.format(formatter));
        Map<String, SEnvWaterMonDay> monMap = sEnvWaterMonDays.stream().collect(Collectors.toMap((item) -> item.getFactoryId() + "_" + item.getOutletId(), Function.identity()));
        List<PcLabelFactory> saveList = new ArrayList<>();
        Map<String,PcLabelValueCodeEnum> resultMap = new HashMap<>();
        //企业有多个排口 , 每个排口 有多条 报警数据
        for (AmProblemFi amProblemFi : amProblemFis) {
            String factoryId = amProblemFi.getFactoryId();
            PcLabelValueCodeEnum valueCodeEnum = resultMap.get(factoryId);
            //该企业已经是最大标签了,不用再计算了
            if(PcLabelValueCodeEnum.CODE_1053.equals(valueCodeEnum)){
                continue;
            }
            //排口id
            String stationId = amProblemFi.getStationId();
            //扩展数据
            String extra = amProblemFi.getExtra();
            JSONObject jsonObject = JSONUtil.parseObj(extra);
            //从扩展数据中 获取 污染物编号
            String pollutantCode = jsonObject.getStr("pollutantCode");
            //污染物允许浓度
            String allowableValue = jsonObject.getStr("allowableValue");
            //排口
            PcOutlet pcOutlet = outletMapper.selectById(stationId);
            //排口编号
            String outletCode = pcOutlet.getOutletCode();
            //1主要排口、2一般排扣
            String outletTypes = pcOutlet.getOutletTypes();
            if("1".equals(outletTypes)){
                BMainPollDisWaterMout pollDisWaterMout = pollDisWaterMoutService.lambdaQuery()
                        .eq(BMainPollDisWaterMout::getFactoryId, factoryId)
                        .eq(BMainPollDisWaterMout::getOutletCode, outletCode)
                        .eq(BMainPollDisWaterMout::getPollutantsType, pollutantCode).one();
                if(pollDisWaterMout == null){
                    continue;
                }
                allowableValue = pollDisWaterMout.getPollutantsMgRate();
            } else if("2".equals(outletTypes)) {
                BMainPollDisWaterOout pollDisWaterOout = pollDisWaterOoutService.lambdaQuery()
                        .eq(BMainPollDisWaterOout::getFactoryId, factoryId)
                        .eq(BMainPollDisWaterOout::getOutletCode, outletCode)
                        .eq(BMainPollDisWaterOout::getPollutantsType, pollutantCode)
                        .one();
                if(pollDisWaterOout == null){
                    continue;
                }
                allowableValue = pollDisWaterOout.getPollutantsMgRate();
            } else {
                //不处理
                continue;
            }

            //排放浓度
            String realEmission = "0";
            // W01018 -> 化学需氧量 cod_emission
            // W21003 -> 氨氮（NH3-N） ammonia_nitrogen_emission
            // W21011 -> 总磷（以P计） phosphorus_concentration_emission
            // W21001 -> 总氮（以N计） nitrogen_concentration_emission
            String key = factoryId + "_" + stationId;
            SEnvWaterMonDay sEnvWaterMonDay = monMap.get(key);
            if(sEnvWaterMonDay == null){
                continue;
            }
            if("W01018".equals(pollutantCode)){
                realEmission = sEnvWaterMonDay.getCodEmission();
            } else if ("W21001".equals(pollutantCode)){
                realEmission = sEnvWaterMonDay.getNitrogenConcentrationEmission();
            } else if ("W21003".equals(pollutantCode)){
                realEmission = sEnvWaterMonDay.getAmmoniaNitrogenEmission();
            } else if ("W21011".equals(pollutantCode)){
                realEmission = sEnvWaterMonDay.getPhosphorusConcentrationEmission();
            } else {
                //不处理
                continue;
            }
            //比较实际排放和允许排放
            PcLabelValueCodeEnum labelValueCodeEnum = verifyParam1(realEmission, allowableValue);
            if(compareValueCode(valueCodeEnum,labelValueCodeEnum) < 0){
                resultMap.put(factoryId,labelValueCodeEnum);
            }
        }
        for (String factoryId : resultMap.keySet()) {
            PcLabelFactory pcLabelFactory = new PcLabelFactory();
            pcLabelFactory.setId(UUID.randomUUID().toString());
            pcLabelFactory.setFactoryId(factoryId);
            pcLabelFactory.setLabelId(labelId);
            pcLabelFactory.setLableUseing("0");
            //根据 允许浓度和排放浓度 计算 标志值
            pcLabelFactory.setLabelValue(resultMap.get(factoryId).getCode());
            pcLabelFactoryService.lambdaUpdate().eq(PcLabelFactory::getFactoryId,factoryId)
                    .eq(PcLabelFactory::getLabelId,labelId)
                    .remove();
            saveList.add(pcLabelFactory);
        }
        pcLabelFactoryService.saveBatch(saveList);
    }

    private PcLabelValueCodeEnum verifyObj(BMainEmissionPollutionWater bMainEmissionPollutionWater){
        PcLabelValueCodeEnum pcLabelValueCodeEnum = verifyParam(bMainEmissionPollutionWater.getActuallyEmittingCod(), bMainEmissionPollutionWater.getAllowableEmissionCod());
        if(PcLabelValueCodeEnum.CODE_1054.equals(pcLabelValueCodeEnum)){
            return pcLabelValueCodeEnum;
        }
        pcLabelValueCodeEnum = verifyParam(bMainEmissionPollutionWater.getActuallyEmittingNhn(), bMainEmissionPollutionWater.getAllowableEmissionNhn());
        if(PcLabelValueCodeEnum.CODE_1054.equals(pcLabelValueCodeEnum)){
            return pcLabelValueCodeEnum;
        }
        pcLabelValueCodeEnum = verifyParam(bMainEmissionPollutionWater.getActuallyEmittingTn(), bMainEmissionPollutionWater.getAllowableEmissionTn());
        if(PcLabelValueCodeEnum.CODE_1054.equals(pcLabelValueCodeEnum)){
            return pcLabelValueCodeEnum;
        }
        pcLabelValueCodeEnum = verifyParam(bMainEmissionPollutionWater.getActuallyEmittingTp(), bMainEmissionPollutionWater.getAllowableEmissionTp());
        return pcLabelValueCodeEnum;
    }

    private static PcLabelValueCodeEnum verifyParam(String param, String allowParam){
        //不是数字
        if(!NumberUtil.isNumber(param) || !NumberUtil.isNumber(allowParam)){
            return null;
        }
        if( NumberUtil.toBigDecimal(param).compareTo(NumberUtil.toBigDecimal(allowParam)) > 0 ){
            //超总量
            return PcLabelValueCodeEnum.CODE_1054;
        }else{
            //不超总量
            return PcLabelValueCodeEnum.CODE_1055;
        }
    }

    private static PcLabelValueCodeEnum verifyParam1(String param, String allowParam){
        //是否数字
        if(!NumberUtil.isNumber(param) || !NumberUtil.isNumber(allowParam)){
            return null;
        }
        BigDecimal paramNum = NumberUtil.toBigDecimal(param);
        BigDecimal allowParamNum = NumberUtil.toBigDecimal(allowParam);
        // 实际值 - 允许值 <= 0 代表无超标
        if (paramNum.subtract(allowParamNum).compareTo(BigDecimal.ZERO) <= 0){
            return PcLabelValueCodeEnum.CODE_1050;
        }
        // 0 < 实际值 - 允许值 < 允许值 超标一倍以内
        if (paramNum.subtract(allowParamNum).compareTo(allowParamNum) <= 0){
            return PcLabelValueCodeEnum.CODE_1051;
        }
        // 允许值 < 实际值 - 允许值 < 允许值 * 2 超标两倍以内
        if (paramNum.subtract(allowParamNum).compareTo(allowParamNum.multiply(new BigDecimal(2))) <= 0){
            return PcLabelValueCodeEnum.CODE_1052;
        }
        //否则就是超标两倍以上
        return PcLabelValueCodeEnum.CODE_1053;
    }

    private static int compareValueCode(PcLabelValueCodeEnum v1,PcLabelValueCodeEnum v2){
        String codeStr = "1050,1051,1052,1053";
        if (v1 != null && v2 != null && codeStr.contains(v1.getCode()) && codeStr.contains(v2.getCode())) {
            return NumberUtil.toBigDecimal(v1.getCode()).compareTo(NumberUtil.toBigDecimal(v2.getCode()));
        } else {
            return 0;
        }
    }
}
