package cn.cecep.talroad.service.strategy.support.jh;

import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.common.redis.service.RedisService;
import cn.cecep.talroad.domain.AmProblemFi;
import cn.cecep.talroad.domain.BasDeviceConfig;
import cn.cecep.talroad.domain.BasThresholdConfig;
import cn.cecep.talroad.domain.MonDevJhReal;
import cn.cecep.talroad.domain.STaskYieldTrend;
import cn.cecep.talroad.enums.DeviceParamTypeEnum;
import cn.cecep.talroad.enums.ProblemTypeEnum;
import cn.cecep.talroad.enums.ThresHoldConfigEnum;
import cn.cecep.talroad.enums.TimeTypeEnum;
import cn.cecep.talroad.enums.YieldTypeEnum;
import cn.cecep.talroad.service.IBasDeviceConfigService;
import cn.cecep.talroad.service.IBasDeviceParamService;
import cn.cecep.talroad.service.IBasThresholdConfigService;
import cn.cecep.talroad.service.IMonDevJhRealService;
import cn.cecep.talroad.service.strategy.YieldStrategyAdapter;
import cn.cecep.talroad.vo.BasDeviceParamVo;
import cn.cecep.talroad.vo.FactoryDeviceVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Auther: cjh
 * @Date: 2023-04-03 11:09
 * @Class: JhJlCountAdapter
 * @Deseription: 任务调度-每小时统计一次装煤次数，推焦次数，并计算产量
 * @Version V1.0
 */
@Slf4j
@Service("JHJLJL")
public class JhJlCountAdapter extends YieldStrategyAdapter {

    @Autowired
    private IBasDeviceConfigService basDeviceConfigService;
    @Autowired
    private IMonDevJhRealService monDevJhRealService;
    @Autowired
    private IBasDeviceParamService basDeviceParamService;
    @Autowired
    private IBasThresholdConfigService basThresholdConfigService;
    @Autowired
    private RedisService redisService;


    /**
     * 查询设备监测数据
     * @param vo
     * @param tempDate
     * @param flag 是否处理历史数据  true 是 false 否
     */
    @Override
    protected void doQueryYieldData(FactoryDeviceVo vo,Date tempDate,boolean flag){
        List<STaskYieldTrend> yieldList = new ArrayList<>();

        Date lastHour = DateUtils.addHours(tempDate,-1);
        Date lastHourBegin = DateUtils.parseFormatDate("yyyy-MM-dd HH:00:00",lastHour);
        Date lastHourEnd = DateUtils.parseFormatDate("yyyy-MM-dd HH:59:59",lastHour);
        MonDevJhReal real = new MonDevJhReal();
        real.setDeviceId(vo.getDeviceId());
        real.setFactoryId(vo.getFactoryId());
        real.setTimeType(TimeTypeEnum.REAL.getCode());
        Map<String,Object> map = new HashMap<>();
        map.put("lastDate",lastHourBegin);
        map.put("currDate",lastHourEnd);
        real.setParams(map);
        List<MonDevJhReal> realList = monDevJhRealService.selectLastHourData(real);
        if(realList!=null&& realList.size()>0) {

            AtomicReference<String> last = new AtomicReference<>();
            last.set(realList.stream().findFirst().get().getJs100());
            AtomicInteger it  = new AtomicInteger();
            realList.forEach(t ->{
                if(StringUtils.isNotEmpty(t.getJs100())){
                    if(Double.valueOf(0).compareTo(Double.valueOf(last.get()))==0&&Double.valueOf(1).compareTo(Double.valueOf(t.getJs100()))==0){
                        it.getAndIncrement();
                    }
                    last.set(t.getJs100());
                }
            });

            AtomicReference<String> lastTm = new AtomicReference<>();
            lastTm.set(realList.stream().findFirst().get().getJs101());
            AtomicInteger itTm  = new AtomicInteger();
            realList.forEach(t ->{
                if(StringUtils.isNotEmpty(t.getJs101())){
                    if(Double.valueOf(0).compareTo(Double.valueOf(lastTm.get()))==0&&Double.valueOf(1).compareTo(Double.valueOf(t.getJs101()))==0){
                        itTm.getAndIncrement();
                    }
                    lastTm.set(t.getJs101());
                }
            });

            long tjcs = itTm.get();
            long zmcs = it.get();


            Date analyseTime = DateUtils.parseFormatDate("yyyy-MM-dd HH", lastHour);
            //根据企业、设备编号、时间查询表里是否存在分析结果，存在则更新装煤次数、推焦次数，不存在则保存
            super.doSaveAnalysisCoal(vo, zmcs, tjcs, analyseTime);

            BigDecimal cl = new BigDecimal(0);
            // 炭化室有效容积
            AtomicReference<Double> yxrj = new AtomicReference<>(0d);
            AtomicReference<String> jlType = new AtomicReference<>("");
            QueryWrapper<BasDeviceConfig> configQueryWrapper = new QueryWrapper<>();
            configQueryWrapper.eq("factory_id", vo.getFactoryId());
            configQueryWrapper.eq("device_id", vo.getDeviceId());
            configQueryWrapper.eq("industry", vo.getIndustry());
            configQueryWrapper.eq("device_type", vo.getDeviceType());
            List<BasDeviceConfig> configList = basDeviceConfigService.list(configQueryWrapper);
            if (configList != null && configList.size() > 0) {
                configList.forEach(p -> {
                    // 判断是否炭化室有效容积
                    if (DeviceParamTypeEnum.TH_TYPE.getCode()
                        .equalsIgnoreCase(p.getParamCode())) {
                        yxrj.set(Double.valueOf(p.getNormalValue()));
                    } else if (DeviceParamTypeEnum.JL_TYPE.getCode()
                        .equalsIgnoreCase(p.getParamCode())) {
                        jlType.set(p.getNormalValue());
                    }
                });
            }

            // 推焦次数趋势数据
            STaskYieldTrend tjYield = super.doBuildTrenData(vo.getFactoryId(), vo.getDeviceId(),YieldTypeEnum.JH_002,lastHourBegin,new BigDecimal(tjcs),flag);
            yieldList.add(tjYield);
            // 装煤次数趋势
            STaskYieldTrend zmYield = super.doBuildTrenData(vo.getFactoryId(), vo.getDeviceId(),YieldTypeEnum.JH_001,lastHourBegin,new BigDecimal(zmcs),flag);
            yieldList.add(zmYield);
            // 焦炉类型不为空，进行后续计算
            if (StringUtils.isNotEmpty(jlType.get()) && yxrj.get() > 0) {
                // 焦炉产量公式，目前写死值，后续待优化 1:顶装焦炉 2：侧装焦炉
                if ("1".equals(jlType.get())) {
                    cl = new BigDecimal(yxrj.get()).multiply(new BigDecimal(0.75))
                        .multiply(new BigDecimal(0.8)).multiply(new BigDecimal(tjcs))
                        .setScale(2,
                            RoundingMode.HALF_UP);
                } else if ("2".equals(jlType.get())) {
                    cl = new BigDecimal(yxrj.get()).multiply(new BigDecimal(0.8))
                        .multiply(new BigDecimal(tjcs)).setScale(2,
                            RoundingMode.HALF_UP);
                }

                // 保存焦炉焦炭产量数据
                super.doSaveAnalysisCokeData(vo, tjcs, analyseTime, cl, yxrj);

                // 焦炉产量趋势
                STaskYieldTrend jlYield = super.doBuildTrenData(vo.getFactoryId(), vo.getDeviceId(),YieldTypeEnum.JH_003,lastHourBegin,cl,flag);
                yieldList.add(jlYield);
            }
            // 布袋除尘器，压差是否频繁超高分析
            try {
                this.doProcessPressData(vo, realList,lastHour);
            } catch (Exception e) {
                log.error("焦化焦炉布袋除尘器，压差是否频繁超高分析异常"+e.getMessage());
            }
        }
        // 批量保存产量
        super.doSaveBatchYieldTrendData(yieldList);
    }

    /**
     * 布袋除尘器，压差是否频繁超高分析
     * @param vo
     * @param currList
     * @param lastHour
     */
    private void doProcessPressData(FactoryDeviceVo vo, List<MonDevJhReal> currList, Date lastHour) {
        List<AmProblemFi> alarmList = new ArrayList<>();
        Date curr = new Date();

        if (currList != null && currList.size() > 0) {
            List<BasDeviceParamVo> paramsList = basDeviceParamService.selectBasDeviceParamByCondition(vo.getDeviceId(), Arrays.asList("jz100","jz101","jz102"));
            // 布袋除尘器，压差是否频繁超高
            processBdData(vo, currList, lastHour, alarmList, curr, paramsList);
            // 静电除尘器
            processJdData(vo, currList, lastHour, alarmList, curr, paramsList);
            // 批量保存报警数据
            super.doSaveBatchAlarm(alarmList);
        }
    }

    /**
     * 布袋除尘
     * @param vo
     * @param currList
     * @param lastHour
     * @param alarmList
     * @param curr
     * @param paramsList
     */
    private void processBdData(FactoryDeviceVo vo, List<MonDevJhReal> currList, Date lastHour, List<AmProblemFi> alarmList, Date curr, List<BasDeviceParamVo> paramsList) {
        String overFlag = redisService.getCacheObject(ProblemTypeEnum.PRESS_OVER_STAND.getCode() + vo.getDeviceId());
        String lowFlag = redisService.getCacheObject(ProblemTypeEnum.PRESS_LOW_STAND.getCode() + vo.getDeviceId());
        if(StringUtils.isEmpty(overFlag)||StringUtils.isEmpty(lowFlag)) {
            //超高次数
            BasThresholdConfig hCount = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.H01.getCode());
            //连续累计超高时间
            BasThresholdConfig hTime = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.H02.getCode());
            //报警间隔时长
            BasThresholdConfig hAlarm = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.H03.getCode());
            // 过低次数
            BasThresholdConfig lCount = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.L01.getCode());
            //连续累计过低时间
            BasThresholdConfig lTime = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.L02.getCode());
            //报警间隔时长
            BasThresholdConfig lAlarm = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.L03.getCode());

            AtomicInteger m = new AtomicInteger();//超高次数
            AtomicInteger h = new AtomicInteger();//连续累计超高时间
            AtomicInteger n = new AtomicInteger();//超低次数
            AtomicInteger l = new AtomicInteger();//连续累计超高时间

            AtomicReference<BigDecimal> maxStandValue = new AtomicReference<>(new BigDecimal(0));
            AtomicReference<BigDecimal> minStandValue = new AtomicReference<>(new BigDecimal(0));
            if (paramsList != null && paramsList.size() > 0) {
                paramsList.forEach(p -> {
                    if ("jz100".equals(p.getParamCodeSvc())) {
                        maxStandValue.set(p.getMaxValue());
                        minStandValue.set(p.getMinValue());
                    }
                });
            }
            if (maxStandValue.get().doubleValue() > 0 || minStandValue.get().doubleValue() > 0) {
                currList.forEach(real -> {
                    if (StringUtils.isEmpty(overFlag)&&maxStandValue.get().doubleValue() > 0) {
                        if (StringUtils.isNotEmpty(real.getG601()) && Double.valueOf(real.getG601()) > maxStandValue.get().doubleValue()) {
                            m.getAndIncrement();
                            h.getAndIncrement();
                        } else {
                            // 压差未超高，则重新计数
                            if (h.get() < hTime.getThresholdValue().intValue()) {
                                h.set(0);
                            }
                        }
                    }
                    if (StringUtils.isEmpty(lowFlag)&&minStandValue.get().doubleValue() > 0) {
                        if (StringUtils.isNotEmpty(real.getG601()) && Double.valueOf(real.getG601()) < minStandValue.get().doubleValue()) {
                            n.getAndIncrement();
                            l.getAndIncrement();
                        } else {
                            // 压差未超低，则重新计数
                            if (l.get() < lTime.getThresholdValue().intValue()) {
                                l.set(0);
                            }
                        }
                    }
                });
            }
            if(StringUtils.isEmpty(overFlag)){
                // 满足条件其中一个条件，即超高报警
                if (m.get() >= hCount.getThresholdValue().intValue() || h.get() >= hTime.getThresholdValue().intValue()) {
                    StringBuffer sb = new StringBuffer();
                    sb.append(vo.getDeviceName()).append("布袋除尘器于").append(DateUtils.parseDateToStr("yyyy-MM-dd HH:00:00", lastHour)).append("开始，进出口压差频繁超过设计标准值高限，可能导致除尘效率变低，存在颗粒物浓度超标风险，请及时排查。");
                    AmProblemFi problemFi = getAmProblemFi(vo, curr, sb, ProblemTypeEnum.PRESS_OVER_STAND,"压差,二次电流,二次电压","jz100,jz101,jz102");
                    alarmList.add(problemFi);
                    redisService.setCacheObject(ProblemTypeEnum.PRESS_OVER_STAND.getCode() + vo.getDeviceId(), vo.getDeviceId(), hAlarm.getThresholdValue().longValue(), TimeUnit.HOURS);
                }
            }
            if(StringUtils.isEmpty(lowFlag)){
                if (n.get() >= lCount.getThresholdValue().intValue() || l.get() >= lTime.getThresholdValue().intValue()) {
                    StringBuffer sb = new StringBuffer();
                    sb.append(vo.getDeviceName()).append("布袋除尘器于").append(DateUtils.parseDateToStr("yyyy-MM-dd HH:00:00", lastHour)).append("开始，进出口压差频繁低于设计标准值下限，可能导致除尘效率变低，请及时排查。");
                    AmProblemFi problemFi = getAmProblemFi(vo, curr, sb, ProblemTypeEnum.PRESS_LOW_STAND,"压差,二次电流,二次电压","jz100,jz101,jz102");
                    alarmList.add(problemFi);
                    redisService.setCacheObject(ProblemTypeEnum.PRESS_LOW_STAND.getCode() + vo.getDeviceId(), vo.getDeviceId(), lAlarm.getThresholdValue().longValue(), TimeUnit.HOURS);
                }
            }
        }
    }

    /**
     * 静电除尘
     *
     * @param vo
     * @param currList
     * @param lastHour
     * @param alarmList
     * @param curr
     * @param paramsList
     */
    private void processJdData(FactoryDeviceVo vo, List<MonDevJhReal> currList, Date lastHour, List<AmProblemFi> alarmList, Date curr, List<BasDeviceParamVo> paramsList) {

        String highFlag = redisService.getCacheObject(ProblemTypeEnum.JDCC_GG.getCode() + vo.getDeviceId());
        String ycFlag = redisService.getCacheObject(ProblemTypeEnum.JDCC_YC.getCode() + vo.getDeviceId());
        String lowFlag = redisService.getCacheObject(ProblemTypeEnum.JDCC_GD.getCode() + vo.getDeviceId());
        if(StringUtils.isEmpty(highFlag)||StringUtils.isEmpty(ycFlag)||StringUtils.isEmpty(lowFlag)) {

            //报警间隔时长
            BasThresholdConfig alarm = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.J01.getCode());
            //超标次数
            BasThresholdConfig hCount = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.J02.getCode());
            //连续累计超高时间
            BasThresholdConfig hTime = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.J03.getCode());
            // 连续累计过低时间
            BasThresholdConfig lTime = basThresholdConfigService.selectByParamCode(ThresHoldConfigEnum.J04.getCode());

            AtomicInteger m = new AtomicInteger();//超标次数
            AtomicInteger h = new AtomicInteger();//连续累计超高时间
            AtomicInteger l = new AtomicInteger();//连续累计过低时间

            AtomicReference<BigDecimal> pressStandValue = new AtomicReference<>(new BigDecimal(0));
            AtomicReference<BigDecimal> elecStandValue = new AtomicReference<>(new BigDecimal(0));
            if (paramsList != null && paramsList.size() > 0) {
                paramsList.forEach(p -> {
                    //二次电压
                    if ("jz102".equals(p.getParamCodeSvc())) {
                        pressStandValue.set(p.getNormalValue());
                    }
                    //二次电流
                    if ("jz101".equals(p.getParamCodeSvc())) {
                        elecStandValue.set(p.getNormalValue());
                    }
                });
            }

            if (pressStandValue.get().doubleValue() > 0 || elecStandValue.get().doubleValue() > 0) {
                Set<String> set = new HashSet<>();
                Set<String> bset = new HashSet<>();
                Double maxElec = elecStandValue.get().multiply(new BigDecimal(1.2)).setScale(2, RoundingMode.HALF_UP).doubleValue();
                Double minElec = elecStandValue.get().multiply(new BigDecimal(0.5)).setScale(2, RoundingMode.HALF_UP).doubleValue();
                Double minPress = pressStandValue.get().multiply(new BigDecimal(0.5)).setScale(2, RoundingMode.HALF_UP).doubleValue();
                Double mElec = elecStandValue.get().multiply(new BigDecimal(1.1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
                Double nElec = elecStandValue.get().multiply(new BigDecimal(0.9)).setScale(2, RoundingMode.HALF_UP).doubleValue();
                Double mPress = pressStandValue.get().multiply(new BigDecimal(1.1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
                Double nPress = pressStandValue.get().multiply(new BigDecimal(0.9)).setScale(2, RoundingMode.HALF_UP).doubleValue();

                currList.forEach(real -> {
                    if (StringUtils.isNotEmpty(real.getJz101())) {
                        // 二次电流大于额定电流1.2倍，二次电压小于额定电压0.5
                        if (StringUtils.isNotEmpty(real.getJz102()) && Double.valueOf(real.getJz101()) > maxElec && Double.valueOf(real.getJz102()) < minPress) {
                            h.getAndIncrement();
                        }
                        // 二次电流小于额定电流0.9 或二次电流大于额定电流1.1
                        if (Double.valueOf(real.getJz101()) < nElec || Double.valueOf(real.getJz101()) > mElec) {
                            m.getAndIncrement();
                            set.add("二次电流");
                            bset.add("二次电流额定电流");
                        }
                        //二次电压正常,二次电流小于额定电流0.5
                        if (StringUtils.isNotEmpty(real.getJz102()) && (Double.valueOf(real.getJz102()) > nPress && Double.valueOf(real.getJz102()) < mPress)
                            && Double.valueOf(real.getJz101()) < minElec) {
                            l.getAndIncrement();
                        } else {
                            if (l.get() < lTime.getThresholdValue().intValue()) {
                                l.set(0);
                            }
                        }
                    }
                    // 二次电压小于额定电压0.9 或二次电压大于额定电压1.1
                    if (StringUtils.isNotEmpty(real.getJz102()) && (Double.valueOf(real.getJz102()) < nPress || Double.valueOf(real.getJz102()) > mPress)) {
                        m.getAndIncrement();
                        set.add("二次电压");
                        bset.add("二次电压额定电压");
                    }

                });
                if (StringUtils.isEmpty(highFlag)) {
                    //二次电流超过额定电流1.2倍且二次电压小于额定电压0.5倍的时间持续10分钟以上,生成报警记录
                    if (h.get() > hTime.getThresholdValue().intValue()) {
                        StringBuffer sb = new StringBuffer();
                        sb.append(vo.getDeviceName()).append("静电除尘器于").append(DateUtils.parseDateToStr("yyyy-MM-dd HH:00:00", lastHour))
                            .append("开始，二次电流超过额定电流1.2倍且二次电压小于额定电压0.5倍的时间持续10分钟以上，可能导致除尘效率变低，存在颗粒物浓度超标风险，请及时排查。");
                        AmProblemFi problemFi = getAmProblemFi(vo, curr, sb, ProblemTypeEnum.JDCC_GG,"压差,二次电流,二次电压","jz100,jz101,jz102");
                        alarmList.add(problemFi);
                        redisService.setCacheObject(ProblemTypeEnum.JDCC_GG.getCode() + vo.getDeviceId(), vo.getDeviceId(), alarm.getThresholdValue().longValue(), TimeUnit.HOURS);
                    }
                }
                if (StringUtils.isEmpty(ycFlag)) {
                    //二次电压小于额定电压0.9 或二次电压大于额定电压1.1
                    if (m.get() >= hCount.getThresholdValue().intValue()) {
                        StringBuffer sb = new StringBuffer();
                        String paramStr = StringUtils.join(",", set);
                        String standStr = StringUtils.join(",", bset);
                        sb.append(vo.getDeviceName()).append("静电除尘器于").append(DateUtils.parseDateToStr("yyyy-MM-dd HH:00:00", lastHour))
                            .append("开始，报警指标" + paramStr + "超过对比标准" + standStr + "10%以上次数超过" + hCount.getThresholdValue().intValue() + "次，可能导致除尘效率变低，存在颗粒物浓度超标风险，请及时排查。");
                        AmProblemFi problemFi = getAmProblemFi(vo, curr, sb, ProblemTypeEnum.JDCC_YC,"压差,二次电流,二次电压","jz100,jz101,jz102");
                        alarmList.add(problemFi);
                        redisService.setCacheObject(ProblemTypeEnum.JDCC_YC.getCode() + vo.getDeviceId(), vo.getDeviceId(), alarm.getThresholdValue().longValue(), TimeUnit.HOURS);
                    }
                }

                if (StringUtils.isEmpty(lowFlag)) {
                    //二次电压正常 且二次电流小于额定电流0.5
                    if (l.get() >= lTime.getThresholdValue().intValue()) {
                        StringBuffer sb = new StringBuffer();
                        sb.append(vo.getDeviceName()).append("静电除尘器于").append(DateUtils.parseDateToStr("yyyy-MM-dd HH:00:00", lastHour))
                            .append("开始，二次电压正常，但二次电流过低，时长超过" + lTime.getThresholdValue().intValue() + "分钟,可能导致除尘效率变低，存在颗粒物浓度超标风险，请及时排查。");
                        AmProblemFi problemFi = getAmProblemFi(vo, curr, sb, ProblemTypeEnum.JDCC_GD,"压差,二次电流,二次电压","jz100,jz101,jz102");
                        alarmList.add(problemFi);
                        redisService.setCacheObject(ProblemTypeEnum.JDCC_GD.getCode() + vo.getDeviceId(), vo.getDeviceId(), alarm.getThresholdValue().longValue(), TimeUnit.HOURS);
                    }
                }
            }
        }
    }

    /**
     * 获取报警数据
     *
     * @param vo
     * @param curr
     * @param sb
     * @param pressOverStand
     * @return
     */
    private AmProblemFi getAmProblemFi(FactoryDeviceVo vo, Date curr, StringBuffer sb, ProblemTypeEnum pressOverStand,String param,String paramProperty) {
        AmProblemFi problemFi = super.doProcessAlaram(vo.getFactoryId(), vo.getDeviceId(), vo.getDeviceName(), curr, new Date(), pressOverStand, sb.toString(), param, paramProperty);
        return problemFi;
    }
}
