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

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.MonDevFsReal;
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.IMonDevFsRealService;
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.List;
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 15:35
 * @Class: FsFslCountAdapter
 * @Deseription: 任务调度-垃圾处理量计算
 * @Version V1.0
 */
@Slf4j
@Service("FSFSLFSL")
public class FsFslCountAdapter extends YieldStrategyAdapter {

    @Autowired
    private IBasDeviceConfigService basDeviceConfigService;
    @Autowired
    private IMonDevFsRealService monDevFsRealService;
    @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){
        Date curr = tempDate;
        Date lastHour = DateUtils.addHours(curr,-1);
        Date lastHourBegin = DateUtils.parseFormatDate("yyyy-MM-dd HH:00:00",lastHour);
        Date lastHourEnd = DateUtils.parseFormatDate("yyyy-MM-dd HH:59:59",lastHour);
        AtomicReference<String> fslType = 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.FS_TYPE.getCode().equalsIgnoreCase(p.getParamCode())) {
                    fslType.set(p.getNormalValue());
                }
            });
        }
        // 焚烧炉类型配置不为空进行计算
        if (StringUtils.isNotEmpty(fslType.get())) {
            if ("1".equals(fslType.get())) {
                // 皮带运输查询1小时内的数据，取平均值
                QueryWrapper<MonDevFsReal> queryWrapper = new QueryWrapper<>();
                queryWrapper.select("fs100");
                queryWrapper.eq("factory_id", vo.getFactoryId());
                queryWrapper.eq("device_id", vo.getDeviceId());
                queryWrapper.eq("time_type", TimeTypeEnum.REAL.getCode());
                queryWrapper.between("data_time",lastHourBegin,lastHourEnd);
                queryWrapper.isNotNull("fs100");
                List<MonDevFsReal> realList = monDevFsRealService.list(queryWrapper);
                if(realList!=null&&realList.size()>0) {
                    // 计算垃圾传输量均值
                    Double avgValue = realList.stream()
                        .mapToDouble(s -> Double.valueOf(s.getFs100())).average().getAsDouble();
                    BigDecimal currentValue = new BigDecimal(avgValue);

                    //皮带运输保存垃圾处理量记录
                    super.doSaveRubbishData(vo, lastHour, currentValue, "皮带运输");
                    // 保存产量趋势
                    STaskYieldTrend trend = super.doBuildTrenData(vo.getFactoryId(),vo.getDeviceId(),YieldTypeEnum.FS_001, lastHourBegin, currentValue, flag);
                    super.doSaveYieldTrendData(trend);
                }
            } else if ("2".equals(fslType.get())) {
                QueryWrapper<MonDevFsReal> queryWrapper = new QueryWrapper<>();
                queryWrapper.select("fs100");
                queryWrapper.eq("factory_id", vo.getFactoryId());
                queryWrapper.eq("device_id", vo.getDeviceId());
                queryWrapper.eq("time_type", TimeTypeEnum.REAL.getCode());
                queryWrapper.between("data_time",lastHourBegin,lastHourEnd);
                queryWrapper.orderByDesc("data_time");
                queryWrapper.isNotNull("fs100");
                queryWrapper.last("limit 1");
                List<MonDevFsReal> realList = monDevFsRealService.list(queryWrapper);

                if(realList!=null&&realList.size()>0) {
                    // 抓斗获取当前1小时最大垃圾处理量
                    Double currHourCl = realList.stream()
                        .mapToDouble(s -> Double.valueOf(s.getFs100())).max().getAsDouble();

                    Date lastTwoHour = DateUtils.addHours(curr, -2);
                    Date lastTwoHourBegin = DateUtils.parseFormatDate("yyyy-MM-dd HH:00:00", lastTwoHour);
                    Date lastTwoHourEnd = DateUtils.parseFormatDate("yyyy-MM-dd HH:59:59", lastTwoHour);

                    QueryWrapper<MonDevFsReal> hourQueryWrapper = new QueryWrapper<>();
                    hourQueryWrapper.select("fs100");
                    hourQueryWrapper.eq("factory_id", vo.getFactoryId());
                    hourQueryWrapper.eq("device_id", vo.getDeviceId());
                    hourQueryWrapper.ge("data_time", lastTwoHourBegin);
                    hourQueryWrapper.le("data_time", lastTwoHourEnd);
                    hourQueryWrapper.orderByDesc("data_time");
                    hourQueryWrapper.isNotNull("fs100");
                    hourQueryWrapper.last("limit 1");
                    // 获取前一个小时最大处理量
                    MonDevFsReal oldData = monDevFsRealService.getOne(hourQueryWrapper);

                    BigDecimal currentValue = null;
                    // 上次垃圾处理量不为空
                    if (oldData != null && StringUtils.isNotEmpty(oldData.getFs100())) {
                        // 上次处理量
                        Double lastCl = Double.valueOf(oldData.getFs100());
                        // 本次处理量小于上次处理量，则为设备重置重新计算，否则最新监测处理量减去前一小时处理量为本小时内处理量
                        if(currHourCl>=lastCl) {
                            currentValue = new BigDecimal(currHourCl)
                                .subtract(new BigDecimal(Double.valueOf(oldData.getFs100())))
                                .setScale(2,
                                    RoundingMode.HALF_UP);
                        }else{
                            currentValue = new BigDecimal(currHourCl).setScale(2,RoundingMode.HALF_UP);
                        }
                    }else{
                        currentValue = new BigDecimal(currHourCl).setScale(2,RoundingMode.HALF_UP);
                    }
                    //抓斗保存垃圾处理量记录
                    super.doSaveRubbishData(vo, lastHour, currentValue, "抓斗");

                    // 保存产量趋势
                    STaskYieldTrend trend = super.doBuildTrenData(vo.getFactoryId(),vo.getDeviceId(),YieldTypeEnum.FS_001, lastHourBegin, currentValue, flag);
                    super.doSaveYieldTrendData(trend);
                }
            }
        }
        // 处理布袋除尘器
        try {
            this.doProcessPressData(vo,lastHour);
        } catch (Exception e) {
            log.error("焚烧布袋除尘器，压差是否频繁超高分析异常"+e.getMessage());
        }
    }

    /**
     * 布袋除尘器，压差是否频繁超高分析
     * @param vo
     * @param lastHour
     */
    private void doProcessPressData(FactoryDeviceVo vo,  Date lastHour) {
        List<AmProblemFi> alarmList = new ArrayList<>();
        Date curr = new Date();
        Date lastHourBegin = DateUtils.parseFormatDate("yyyy-MM-dd HH:00:00",lastHour);
        Date lastHourEnd = DateUtils.parseFormatDate("yyyy-MM-dd HH:59:59",lastHour);
        QueryWrapper<MonDevFsReal> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("factory_id", vo.getFactoryId());
        queryWrapper.eq("device_id", vo.getDeviceId());
        queryWrapper.eq("time_type", TimeTypeEnum.REAL.getCode());
        queryWrapper.between("data_time",lastHourBegin,lastHourEnd);
        List<MonDevFsReal> realList = monDevFsRealService.list(queryWrapper);

        // 布袋除尘器，压差是否频繁超高
        if (realList != null && realList.size() > 0) {
            List<BasDeviceParamVo> paramsList = basDeviceParamService.selectBasDeviceParamByCondition(vo.getDeviceId(), Arrays.asList("fz108"));
            // 布袋除尘器
            processBdData(vo, realList, 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<MonDevFsReal> 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 ("fz108".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.getFz108()) && Double.valueOf(real.getFz108()) > 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.getFz108()) && Double.valueOf(real.getFz108()) < 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);
                    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);
                    alarmList.add(problemFi);
                    redisService.setCacheObject(ProblemTypeEnum.PRESS_LOW_STAND.getCode() + vo.getDeviceId(), vo.getDeviceId(), lAlarm.getThresholdValue().longValue(), TimeUnit.HOURS);
                }
            }
        }
    }


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