package com.prolog.rdc.tms.service.message.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.prolog.cs.platform.power.model.Organization;
import com.prolog.cs.platform.power.model.enterprise.User;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.RestrictionBuilder;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.config.enums.MessageConfigConditionEnum;
import com.prolog.rdc.tms.config.enums.MessageConfigNoticeToTypeEnum;
import com.prolog.rdc.tms.config.enums.MessageConfigStatusEnum;
import com.prolog.rdc.tms.constant.BussinessConstant;
import com.prolog.rdc.tms.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.constant.SeriaNnumberConstant;
import com.prolog.rdc.tms.dao.mapper.TmsAppointmentDetailMapper;
import com.prolog.rdc.tms.dao.mapper.TmsAppointmentHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.TmsBaseDeviceMapper;
import com.prolog.rdc.tms.dao.mapper.TmsLoadingBillDetailMapper;
import com.prolog.rdc.tms.dao.mapper.TmsLoadingBillHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.TmsMessageConfigMapper;
import com.prolog.rdc.tms.dao.mapper.TmsMessageMapper;
import com.prolog.rdc.tms.dao.mapper.TmsMessageSendLogMapper;
import com.prolog.rdc.tms.dao.mapper.TmsShipbillDetailMapper;
import com.prolog.rdc.tms.dao.mapper.TmsShipbillHeaderMapper;
import com.prolog.rdc.tms.model.dto.e6.EquipInfoDTO;
import com.prolog.rdc.tms.model.dto.g7.CurrentTemperatureDTO;
import com.prolog.rdc.tms.model.dto.message.ChannelMessageDTO;
import com.prolog.rdc.tms.model.dto.message.ChannelMessageUserDTO;
import com.prolog.rdc.tms.model.dto.message.MessageConfigConditionDTO;
import com.prolog.rdc.tms.model.dto.message.MessageConfigDTO;
import com.prolog.rdc.tms.model.dto.message.MessageConfigNoticeToDTO;
import com.prolog.rdc.tms.model.dto.message.SendMessageDTO;
import com.prolog.rdc.tms.model.entity.TmsAppointmentDetailModel;
import com.prolog.rdc.tms.model.entity.TmsAppointmentHeaderModel;
import com.prolog.rdc.tms.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.model.entity.TmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.model.entity.TmsShipbillDetailModel;
import com.prolog.rdc.tms.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.model.entity.line.TmsBaseDeviceModel;
import com.prolog.rdc.tms.model.entity.message.TmsMessageConfigModel;
import com.prolog.rdc.tms.model.entity.message.TmsMessageModel;
import com.prolog.rdc.tms.model.entity.message.TmsMessageSendLogModel;
import com.prolog.rdc.tms.model.enums.MessageAlarmTypeEnum;
import com.prolog.rdc.tms.model.enums.MessageOrderTypeEnum;
import com.prolog.rdc.tms.model.enums.MessageTimeUnitEnum;
import com.prolog.rdc.tms.model.vo.e6.EquipInfoVO;
import com.prolog.rdc.tms.model.vo.g7.CurrentTemperatureVO;
import com.prolog.rdc.tms.model.vo.message.MessageJobVO;
import com.prolog.rdc.tms.proxy.UserProxy;
import com.prolog.rdc.tms.rmi.feign.InterfaceFeign;
import com.prolog.rdc.tms.service.SysCodeengineService;
import com.prolog.rdc.tms.service.message.MessageChannel;
import com.prolog.rdc.tms.service.message.MessageConfigService;
import com.prolog.rdc.tms.service.message.SendMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author hongbo.pan
 * @date 2022/11/16
 */
@Slf4j
@Service
public class SendMessageServiceImpl implements SendMessageService {

    private static final String TOPIC = "SendMessageServiceImpl";

    @Autowired
    private TmsMessageConfigMapper tmsMessageConfigMapper;

    @Autowired
    private MessageConfigService messageConfigService;

    @Autowired
    private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

    @Autowired
    private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

    @Autowired
    private TmsAppointmentDetailMapper tmsAppointmentDetailMapper;

    @Autowired
    private TmsAppointmentHeaderMapper tmsAppointmentHeaderMapper;

    @Autowired
    private TmsLoadingBillHeaderMapper tmsLoadingBillHeaderMapper;

    @Autowired
    private UserProxy userProxy;

    @Autowired
    private MessageChannelFactory factory;

    @Autowired
    private SysCodeengineService sysCodeengineService;

    @Autowired
    private TmsMessageSendLogMapper tmsMessageSendLogMapper;

    @Autowired
    private TmsMessageMapper tmsMessageMapper;

    @Autowired
    private TmsBaseDeviceMapper tmsBaseDeviceMapper;

    @Autowired
    private InterfaceFeign interfaceFeign;

    @Autowired
    private TmsShipbillDetailMapper tmsShipbillDetailMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void send(SendMessageDTO sendMessageDTO) {
        log.info("topic={},title={},sendMessageDTO={}", TOPIC, "send", JSON.toJSONString(sendMessageDTO));
        UserEntity user = sendMessageDTO.getUser();
        Criteria criteria = Criteria.forClass(TmsMessageConfigModel.class);
        Restriction restriction = new RestrictionBuilder()
                .eq("type",sendMessageDTO.getMessageType())
                .eq("status", MessageConfigStatusEnum.ENABLE.getCode())
                .eq("enterpriseId",user.getEnterpriseId())
                .build();
        criteria.setRestriction(restriction);
        List<TmsMessageConfigModel> tmsMessageConfigModelList = tmsMessageConfigMapper.findByCriteria(criteria);
        log.info("topic={},title={},type={},enterpriseId={}", TOPIC, "send", sendMessageDTO.getMessageType(), user.getEnterpriseId());
        if (CollectionUtil.isNotEmpty(tmsMessageConfigModelList)) {
            Map<String, String> billCodeMap = Maps.newHashMap();
            List<TmsShipbillHeaderModel> tmsShipbillHeaderModelList = buildBillCodeMapAndReturnShipBill(sendMessageDTO, billCodeMap);
            tmsMessageConfigModelList.forEach(tmsMessageConfigModel -> {
                MessageConfigDTO messageConfigDTO = messageConfigService.findById(tmsMessageConfigModel.getId());
                //满足要求
                if (shipBillMatchCondition(tmsShipbillHeaderModelList, messageConfigDTO.getConfigConditionDTOList())) {
                    String content = buildContent(messageConfigDTO.getContent(), billCodeMap);
                    messageConfigDTO.setContent(content);
                    List<ChannelMessageUserDTO> channelMessageUserDTOList = buildChannelMessageUserDTO(messageConfigDTO, billCodeMap);
                    ChannelMessageDTO channelMessageDTO = new ChannelMessageDTO();
                    channelMessageDTO.setMessageConfigDTO(messageConfigDTO);
                    channelMessageDTO.setSendMessageDTO(sendMessageDTO);
                    channelMessageDTO.setChannelMessageUserDTOList(channelMessageUserDTOList);
                    channelMessageDTO.setUser(user);
                    channelMessageDTO.setShipbillId(billCodeMap.getOrDefault(getKey(MessageOrderTypeEnum.SHIP_NO), StrUtil.EMPTY));
                    Arrays.stream(channelMessageDTO.getMessageConfigDTO().getSendType().split(",")).forEach(sendType -> {
                        MessageChannel channel = factory.getChannel(sendType);
                        try {
                            channel.send(channelMessageDTO);
                            successSendLog(channelMessageDTO, sendType);
                        } catch (Exception e) {
                            errorSendLog(channelMessageDTO, sendType, e);
                        }
                    });
                }
            });
        } else {
            log.info("topic={},title={},type={},enterpriseId={},启用消息配置不存在", TOPIC, "send", sendMessageDTO.getMessageType(), user.getEnterpriseId());
        }
    }

    @Override
    public void sendLocal(SendMessageDTO sendMessageDTO) {
        sendMessageDTO.setUser(PlgFxUsrUtils.getUserEntity());
        send(sendMessageDTO);
    }

    @Override
    public void sendPickUpMessage(MessageJobVO vo) {
        String title = "sendPickUpMessage";
        StopWatch stopWatch = new StopWatch(title);
        stopWatch.start();
        log.info("{} 未及时提货消息发送任务开始", title);
        TmsMessageConfigModel messageConfigModel = getMessageConfig(vo, MessageAlarmTypeEnum.PICK_UP.getCode());
        if (ObjectUtil.isNotNull(messageConfigModel)) {
            log.info("{} 未及时提货消息配置={}", title, JSON.toJSONString(messageConfigModel));
            List<TmsShipbillHeaderModel> shipbillHeaderModelList = getMatchShipBill(vo, Lists.newArrayList("115", "120"));
            log.info("{} 根据时间，间隔过滤前运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
            if (CollectionUtil.isNotEmpty(shipbillHeaderModelList)) {
                Integer interval = getAlarmInterval(messageConfigModel.getAlarmInterval(), messageConfigModel.getAlarmIntervalUnit());
                log.info("{} 间隔时间（秒）={}", title, interval);
                shipbillHeaderModelList = shipbillHeaderModelList.stream().filter(shipbillHeaderModel -> {
                    log.info("{} 运单信息={}", title, JSON.toJSONString(shipbillHeaderModel));
                    if (ObjectUtil.isNotNull(shipbillHeaderModel.getEstimatedPickupStartTime()) && ObjectUtil.isNotNull(shipbillHeaderModel.getEstimatedPickupEndTime())) {
                        Date startDate = getOffsetDate(shipbillHeaderModel.getEstimatedPickupStartTime(), messageConfigModel.getAlarmStartOffset() * -1, messageConfigModel.getAlarmStartOffsetUnit());
                        Date endDate = getOffsetDate(shipbillHeaderModel.getEstimatedPickupEndTime(), messageConfigModel.getAlarmEndOffset(), messageConfigModel.getAlarmEndOffsetUnit());
                        log.info("{} 运单id={}，开始时间={}，结束时间={}，当前时间={}", title, shipbillHeaderModel.getShipbillId(), DateUtil.formatDateTime(startDate), DateUtil.formatDateTime(endDate), DateUtil.now());
                        if (startDate.before(DateUtil.date()) && endDate.after(DateUtil.date())) {
                            TmsMessageModel lastMessage = tmsMessageMapper.findOneByCondition(vo.getEnterpriseId(), shipbillHeaderModel.getShipbillId(), MessageAlarmTypeEnum.PICK_UP.getCode());
                            return intervalCompare(title, interval, lastMessage);
                        }
                    }
                    return Boolean.FALSE;
                }).collect(Collectors.toList());
                log.info("{} 根据时间，间隔过滤后运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
                sendShipBillMessage(shipbillHeaderModelList, vo, MessageAlarmTypeEnum.PICK_UP.getCode());
            }
        } else {
            log.warn("{} 未及时提货消息配置不存在", title);
        }
        stopWatch.stop();
        log.info("{} 未及时提货消息发送任务结束，耗时={}", title, stopWatch.prettyPrint());
    }

    @Override
    public void sendDeliveryMessage(MessageJobVO vo) {
        String title = "sendDeliveryMessage";
        StopWatch stopWatch = new StopWatch(title);
        stopWatch.start();
        log.info("{} 未及时送达消息发送任务开始", title);
        TmsMessageConfigModel messageConfigModel = getMessageConfig(vo, MessageAlarmTypeEnum.DELIVERY.getCode());
        if (ObjectUtil.isNotNull(messageConfigModel)) {
            log.info("{} 未及时送达消息配置={}", title, JSON.toJSONString(messageConfigModel));
            List<TmsShipbillHeaderModel> shipbillHeaderModelList = getMatchShipBill(vo, Lists.newArrayList("145", "150"));
            log.info("{} 根据时间，间隔过滤前运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
            if (CollectionUtil.isNotEmpty(shipbillHeaderModelList)) {
                Integer interval = getAlarmInterval(messageConfigModel.getAlarmInterval(), messageConfigModel.getAlarmIntervalUnit());
                log.info("{} 间隔时间（秒）={}", title, interval);
                shipbillHeaderModelList = shipbillHeaderModelList.stream().filter(shipbillHeaderModel -> {
                    log.info("{} 运单信息={}", title, JSON.toJSONString(shipbillHeaderModel));
                    if (ObjectUtil.isNotNull(shipbillHeaderModel.getEstimatedDeliveryStartTime()) && ObjectUtil.isNotNull(shipbillHeaderModel.getEstimatedDeliveryEndTime())) {
                        Date startDate = getOffsetDate(shipbillHeaderModel.getEstimatedDeliveryStartTime(), messageConfigModel.getAlarmStartOffset() * -1, messageConfigModel.getAlarmStartOffsetUnit());
                        Date endDate = getOffsetDate(shipbillHeaderModel.getEstimatedDeliveryEndTime(), messageConfigModel.getAlarmEndOffset(), messageConfigModel.getAlarmEndOffsetUnit());
                        log.info("{} 运单id={}，开始时间={}，结束时间={}，当前时间={}", title, shipbillHeaderModel.getShipbillId(), DateUtil.formatDateTime(startDate), DateUtil.formatDateTime(endDate), DateUtil.now());
                        if (startDate.before(DateUtil.date()) && endDate.after(DateUtil.date())) {
                            TmsMessageModel lastMessage = tmsMessageMapper.findOneByCondition(vo.getEnterpriseId(), shipbillHeaderModel.getShipbillId(), MessageAlarmTypeEnum.DELIVERY.getCode());
                            return intervalCompare(title, interval, lastMessage);
                        }
                    }
                    return Boolean.FALSE;
                }).collect(Collectors.toList());
                log.info("{} 根据时间，间隔过滤后运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
                sendShipBillMessage(shipbillHeaderModelList, vo, MessageAlarmTypeEnum.DELIVERY.getCode());
            }
        } else {
            log.warn("{} 未及时送达消息配置不存在", title);
        }
        stopWatch.stop();
        log.info("{} 未及时送达消息发送任务结束，耗时={}", title, stopWatch.prettyPrint());
    }



    @Override
    public void sendReceiptMessage(MessageJobVO vo) {
        String title = "sendReceiptMessage";
        StopWatch stopWatch = new StopWatch(title);
        stopWatch.start();
        log.info("{} 未及时纸质回单消息发送任务开始", title);
        TmsMessageConfigModel messageConfigModel = getMessageConfig(vo, MessageAlarmTypeEnum.RECEIPT.getCode());
        if (ObjectUtil.isNotNull(messageConfigModel)) {
            log.info("{} 未及时纸质回单消息配置={}", title, JSON.toJSONString(messageConfigModel));
            List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.queryLoadingBillDetail(vo);
            if (CollectionUtil.isNotEmpty(tmsLoadingBillDetailModelList)) {
                Integer interval = getAlarmInterval(messageConfigModel.getAlarmInterval(), messageConfigModel.getAlarmIntervalUnit());
                log.info("{} 间隔时间（秒）={}", title, interval);
                List<TmsShipbillHeaderModel> shipbillHeaderModelList = tmsShipbillHeaderMapper.findByIds(TmsShipbillHeaderModel.class,
                        tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getShipbillId).distinct().collect(Collectors.toList()).toArray(), null);
                log.info("{} 根据时间，间隔过滤前运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
                shipbillHeaderModelList = shipbillHeaderModelList.stream().filter(shipbillHeaderModel -> {
                    log.info("{} 运单信息={}", title, JSON.toJSONString(shipbillHeaderModel));
                    if (ObjectUtil.isNotNull(shipbillHeaderModel.getReturnOrderDeadline())) {
                        Date receiptDate = DateUtil.offsetDay(shipbillHeaderModel.getCreatetime(), shipbillHeaderModel.getReturnOrderDeadline());
                        Date startDate = getOffsetDate(receiptDate, messageConfigModel.getAlarmStartOffset() * -1, messageConfigModel.getAlarmStartOffsetUnit());
                        Date endDate = getOffsetDate(receiptDate, messageConfigModel.getAlarmEndOffset(), messageConfigModel.getAlarmEndOffsetUnit());
                        log.info("{} 运单id={}，开始时间={}，结束时间={}，当前时间={}", title, shipbillHeaderModel.getShipbillId(), DateUtil.formatDateTime(startDate), DateUtil.formatDateTime(endDate), DateUtil.now());
                        if (startDate.before(DateUtil.date()) && endDate.after(DateUtil.date())) {
                            TmsMessageModel lastMessage = tmsMessageMapper.findOneByCondition(vo.getEnterpriseId(), shipbillHeaderModel.getShipbillId(), MessageAlarmTypeEnum.RECEIPT.getCode());
                            return intervalCompare(title, interval, lastMessage);
                        }
                    }
                    return Boolean.FALSE;
                }).collect(Collectors.toList());
                log.info("{} 根据时间，间隔过滤后运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
                sendShipBillMessage(shipbillHeaderModelList, vo, MessageAlarmTypeEnum.RECEIPT.getCode());
            }
        } else {
            log.warn("{} 未及时纸质回单消息配置不存在", title);
        }
        stopWatch.stop();
        log.info("{} 未及时纸质回单消息发送任务结束，耗时={}", title, stopWatch.prettyPrint());
    }

    @Override
    public void sendTemperatureMessage(MessageJobVO vo) {
        String title = "sendTemperatureMessage";
        StopWatch stopWatch = new StopWatch(title);
        stopWatch.start();
        log.info("{} 温度预警消息发送任务开始", title);
        TmsMessageConfigModel messageConfigModel = getMessageConfig(vo, MessageAlarmTypeEnum.TEMPERATURE.getCode());
        if (ObjectUtil.isNotNull(messageConfigModel)) {
            log.info("{} 温度预警消息配置={}", title, JSON.toJSONString(messageConfigModel));
            List<TmsShipbillHeaderModel> shipbillHeaderModelList = getMatchShipBill(vo, Lists.newArrayList("145", "150"));
            log.info("{} 根据设备，温度，间隔过滤前运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
            if (CollectionUtil.isNotEmpty(shipbillHeaderModelList)) {
                Integer interval = getAlarmInterval(messageConfigModel.getAlarmInterval(), messageConfigModel.getAlarmIntervalUnit());
                log.info("{} 间隔时间（秒）={}", title, interval);
                shipbillHeaderModelList = shipbillHeaderModelList.stream().filter(shipbillHeaderModel -> {
                    log.info("{} 运单信息={}", title, JSON.toJSONString(shipbillHeaderModel));
                    TmsMessageModel lastMessage = tmsMessageMapper.findOneByCondition(vo.getEnterpriseId(), shipbillHeaderModel.getShipbillId(), MessageAlarmTypeEnum.TEMPERATURE.getCode());
                    if (intervalCompare(title, interval, lastMessage) && StrUtil.isNotBlank(shipbillHeaderModel.getVehicleDeviceId())) {
                        TmsBaseDeviceModel tmsBaseDeviceModel = tmsBaseDeviceMapper.findById(shipbillHeaderModel.getVehicleDeviceId().split(",")[0], TmsBaseDeviceModel.class);
                        List<TmsShipbillDetailModel> tmsShipbillDetailModelList = getShipBillDetail(vo, shipbillHeaderModel.getShipbillId());
                        if (BussinessConstant.E6.equals(tmsBaseDeviceModel.getCompany())) {
                            EquipInfoVO equipInfoVO = new EquipInfoVO();
                            equipInfoVO.setEquipCode(shipbillHeaderModel.getVehicleDeviceCode());
                            RestMessage<List<EquipInfoDTO>> equipInfoReal = null;
                            try {
                                equipInfoReal = interfaceFeign.getEquipInfoReal(equipInfoVO);
                            } catch (Exception e) {
                                log.error("{} getEquipInfoReal", title, e);
                            }  finally {
                                log.info("{} getEquipInfoReal request={},response={}", title, JSON.toJSONString(equipInfoVO), JSON.toJSONString(equipInfoReal));
                            }
                            if (ObjectUtil.isNotNull(equipInfoReal) && equipInfoReal.isSuccess() && CollectionUtil.isNotEmpty(equipInfoReal.getData())) {
                                EquipInfoDTO equipInfoDTO = equipInfoReal.getData().get(0);
                                Optional<BigDecimal> lowerLimit = tmsShipbillDetailModelList.stream().map(TmsShipbillDetailModel::getTemperatureCtlLowerLimit).filter(ObjectUtil::isNotNull).max(BigDecimal::compareTo);
                                if (lowerLimit.isPresent() && NumberUtil.isLess(equipInfoDTO.getT1(), lowerLimit.get())) {
                                    return Boolean.TRUE;
                                }
                                Optional<BigDecimal> upperLimit = tmsShipbillDetailModelList.stream().map(TmsShipbillDetailModel::getTemperatureCtlUpperLimit).filter(ObjectUtil::isNotNull).min(BigDecimal::compareTo);
                                if (upperLimit.isPresent() && NumberUtil.isGreater(equipInfoDTO.getT1(), upperLimit.get())) {
                                    return Boolean.TRUE;
                                }
                            }
                        }
                        if (BussinessConstant.G7.equals(tmsBaseDeviceModel.getCompany())) {
                            CurrentTemperatureVO currentTemperatureVO = new CurrentTemperatureVO();
                            currentTemperatureVO.setGpsnos(shipbillHeaderModel.getVehicleDeviceCode());
                            RestMessage<List<CurrentTemperatureDTO>> currentTemperatureInfo = null;
                            try {
                                currentTemperatureInfo = interfaceFeign.currentTemperatureExecute(currentTemperatureVO);
                            } catch (Exception e) {
                                log.error("{} currentTemperatureExecute", title, e);
                            }  finally {
                                log.info("{} currentTemperatureExecute request={},response={}", title, JSON.toJSONString(currentTemperatureVO), JSON.toJSONString(currentTemperatureInfo));
                            }
                            if (ObjectUtil.isNotNull(currentTemperatureInfo) && currentTemperatureInfo.isSuccess() && CollectionUtil.isNotEmpty(currentTemperatureInfo.getData())) {
                                CurrentTemperatureDTO currentTemperatureDTO = currentTemperatureInfo.getData().get(0);
                                BigDecimal temperature = NumberUtil.toBigDecimal(currentTemperatureDTO.getProbeInfo().getT0Temperature());
                                if ("1".equals(currentTemperatureDTO.getColdchaintype())) {
                                    temperature = NumberUtil.toBigDecimal(currentTemperatureDTO.getProbeInfo().getT1Temperature());
                                }
                                Optional<BigDecimal> lowerLimit = tmsShipbillDetailModelList.stream().map(TmsShipbillDetailModel::getTemperatureCtlLowerLimit).filter(ObjectUtil::isNotNull).max(BigDecimal::compareTo);
                                if (lowerLimit.isPresent() && NumberUtil.isLess(temperature, lowerLimit.get())) {
                                    return Boolean.TRUE;
                                }
                                Optional<BigDecimal> upperLimit = tmsShipbillDetailModelList.stream().map(TmsShipbillDetailModel::getTemperatureCtlUpperLimit).filter(ObjectUtil::isNotNull).min(BigDecimal::compareTo);
                                if (upperLimit.isPresent() && NumberUtil.isGreater(temperature, upperLimit.get())) {
                                    return Boolean.TRUE;
                                }
                            }
                        }
                    }
                    return Boolean.FALSE;
                }).collect(Collectors.toList());
                log.info("{} 根据设备，温度，间隔过滤后运单={}", title, JSON.toJSONString(shipbillHeaderModelList));
                sendShipBillMessage(shipbillHeaderModelList, vo, MessageAlarmTypeEnum.TEMPERATURE.getCode());
            }
        } else {
            log.warn("{} 温度预警消息配置不存在", title);
        }
        stopWatch.stop();
        log.info("{} 温度预警消息发送任务结束，耗时={}", title, stopWatch.prettyPrint());
    }

    /**
     * 发送成功日志
     * @param channelMessageDTO
     * @param sendType
     */
    private void successSendLog(ChannelMessageDTO channelMessageDTO, String sendType) {
        TmsMessageSendLogModel sendLogModel = buildSendLog(channelMessageDTO, sendType);
        sendLogModel.setSendStatus(DataDictionaryConstant.MESSAGE_SEND_LOG_SUCCESS);
        tmsMessageSendLogMapper.save(sendLogModel);
    }

    /**
     * 发送失败日志
     * @param channelMessageDTO
     * @param sendType
     * @param e
     */
    private void errorSendLog(ChannelMessageDTO channelMessageDTO, String sendType, Exception e) {
        TmsMessageSendLogModel sendLogModel = buildSendLog(channelMessageDTO, sendType);
        sendLogModel.setSendStatus(DataDictionaryConstant.MESSAGE_SEND_LOG_FAIL);
        sendLogModel.setErrorMsg(ExceptionUtil.stacktraceToString(e));
        tmsMessageSendLogMapper.save(sendLogModel);
    }

    /**
     * 构建发送日志
     * @param channelMessageDTO
     * @return
     */
    private TmsMessageSendLogModel buildSendLog(ChannelMessageDTO channelMessageDTO, String sendType) {
        TmsMessageSendLogModel sendLogModel = new TmsMessageSendLogModel();
        sendLogModel.setId(Long.valueOf(sysCodeengineService.getCodeNumberByCode(SeriaNnumberConstant.TMS_MESSAGE_SEND_LOG_ID, "L")));
        sendLogModel.setMessageConfigId(channelMessageDTO.getMessageConfigDTO().getId());
        sendLogModel.setMessageName(channelMessageDTO.getMessageConfigDTO().getName());
        sendLogModel.setMessageType(channelMessageDTO.getMessageConfigDTO().getType());
        sendLogModel.setSendType(sendType);
        sendLogModel.setOrderType(channelMessageDTO.getSendMessageDTO().getMessageOrderType());
        sendLogModel.setOrderNo(channelMessageDTO.getSendMessageDTO().getBillCode().stream().collect(Collectors.joining(",")));
        sendLogModel.setContent(channelMessageDTO.getMessageConfigDTO().getContent());
        sendLogModel.setCondition(channelMessageDTO.getMessageConfigDTO().getConditionName());
        if (CollectionUtil.isNotEmpty(channelMessageDTO.getChannelMessageUserDTOList())) {
            sendLogModel.setNoticeTo(channelMessageDTO.getChannelMessageUserDTOList().stream().map(ChannelMessageUserDTO::getNickName).collect(Collectors.joining(",")));
        }
        sendLogModel.setSendTime(new Date());
        sendLogModel.setRetryCount(0L);
        sendLogModel.setRequestParam(JSON.toJSONString(channelMessageDTO));
        sendLogModel.setEnterpriseId(channelMessageDTO.getUser().getEnterpriseId());
        sendLogModel.setEnterpriseName(channelMessageDTO.getUser().getEnterpriseName());
        sendLogModel.setCreatetime(new Date());
        sendLogModel.setCreateperson(channelMessageDTO.getUser().getNickname());
        sendLogModel.setUpdatetime(new Date());
        sendLogModel.setUpdateperson(channelMessageDTO.getUser().getNickname());
        sendLogModel.setMessageNoticeType(channelMessageDTO.getMessageConfigDTO().getNoticeType());
        sendLogModel.setShipbillId(channelMessageDTO.getShipbillId());
        return sendLogModel;
    }

    /**
     * 构建发送对象
     * @param messageConfigDTO
     * @param billCodeMap
     * @return
     */
    private List<ChannelMessageUserDTO> buildChannelMessageUserDTO(MessageConfigDTO messageConfigDTO, Map<String, String> billCodeMap) {
        List<MessageConfigNoticeToDTO>  messageConfigNoticeToDTOList = messageConfigDTO.getConfigNoticeToDTOList();
        List<ChannelMessageUserDTO> channelMessageUserDTOList = Lists.newArrayList();
        List<User> allNoticeUser = Lists.newArrayList();
        List<String> userIdList = Lists.newArrayList();
        if (CollectionUtil.isNotEmpty(messageConfigNoticeToDTOList)) {
            Map<String, List<MessageConfigNoticeToDTO>> noticeToMap = messageConfigNoticeToDTOList.stream()
                    .collect(Collectors.groupingBy(MessageConfigNoticeToDTO::getType));
            List<MessageConfigNoticeToDTO> roleList = noticeToMap.get(MessageConfigNoticeToTypeEnum.ROLE.getCode());
            List<MessageConfigNoticeToDTO> userList = noticeToMap.get(MessageConfigNoticeToTypeEnum.USER.getCode());
            if (CollectionUtil.isNotEmpty(roleList)) {
                roleList.stream().forEach(messageConfigNoticeToDTO ->
                        Arrays.stream(messageConfigNoticeToDTO.getNoticeToId().split(",")).forEach(roleId -> {
                        List<User> users = userProxy.getUserByRoleId(roleId);
                        if (CollectionUtil.isNotEmpty(users)) {
                            allNoticeUser.addAll(users);
                        }
                }));
            }
            if (CollectionUtil.isNotEmpty(userList)) {
                userIdList.addAll(userList.stream().flatMap(messageConfigNoticeToDTO -> Arrays.stream(messageConfigNoticeToDTO.getNoticeToId().split(",")))
                        .distinct().collect(Collectors.toList()));
            }
        }
        if (DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeDriver())) {
            String loadingIds = billCodeMap.get(getKey(MessageOrderTypeEnum.LOADING_NO));
            if (StrUtil.isNotBlank(loadingIds)) {
                List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModelList = tmsLoadingBillHeaderMapper.findByIds(
                        TmsLoadingBillHeaderModel.class, loadingIds.split(","), null);
                userIdList.addAll(tmsLoadingBillHeaderModelList.stream().map(TmsLoadingBillHeaderModel::getDriverId)
                        .filter(ObjectUtil::isNotNull).distinct().map(String::valueOf).collect(Collectors.toList()));
            }
        }
        if (CollectionUtil.isNotEmpty(userIdList)) {
            List<User> users = userProxy.getUserByIdList(userIdList.stream().collect(Collectors.joining(",")));
            if (CollectionUtil.isNotEmpty(users)) {
                allNoticeUser.addAll(users);
            }
        }
        if (DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeCargoowner())
            || DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeCarrier())
                || DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeShipper())
                || DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeConsignee())) {

            String shipBillIdList = billCodeMap.get(getKey(MessageOrderTypeEnum.SHIP_NO));
            if (StrUtil.isNotBlank(shipBillIdList)) {
                List<TmsShipbillHeaderModel> tmsShipbillHeaderModelList = tmsShipbillHeaderMapper.findByIds(TmsShipbillHeaderModel.class,
                        shipBillIdList.split(","), null);
                if (CollectionUtil.isNotEmpty(tmsShipbillHeaderModelList)) {
                    if (DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeCargoowner())){
                        List<Long> cargoOwnerIdList = tmsShipbillHeaderModelList.stream().map(TmsShipbillHeaderModel::getCargoOwnerId).filter(ObjectUtil::isNotNull).distinct().collect(Collectors.toList());
                        if (CollectionUtil.isNotEmpty(cargoOwnerIdList)) {
                            cargoOwnerIdList.forEach(cargoOwnerId -> allNoticeUser.addAll(userProxy.getEnterpriseUsers(messageConfigDTO.getEnterpriseId().toString(), BussinessConstant.USER_TYPE_HZ, cargoOwnerId.toString())));
                        }
                    }
                    if (DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeCarrier())){
                        List<Long> carrierIdList = tmsShipbillHeaderModelList.stream().map(TmsShipbillHeaderModel::getCarrierId).filter(ObjectUtil::isNotNull).distinct().collect(Collectors.toList());
                        if (CollectionUtil.isNotEmpty(carrierIdList)) {
                            carrierIdList.forEach(carrierId -> allNoticeUser.addAll(userProxy.getEnterpriseUsers(messageConfigDTO.getEnterpriseId().toString(), BussinessConstant.USER_TYPE_CYS, carrierId.toString())));
                        }
                    }
                    if (DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeShipper())){
                        tmsShipbillHeaderModelList.stream().forEach(tmsShipbillHeaderModel -> {
                            String userCategory = StrUtil.EMPTY;
                            if (DataDictionaryConstant.SHIPPER_TYPE_KH.equals(tmsShipbillHeaderModel.getShipperType())) {
                                userCategory = BussinessConstant.USER_TYPE_KH;
                            } else if (DataDictionaryConstant.SHIPPER_TYPE_CK.equals(tmsShipbillHeaderModel.getShipperType())) {
                                userCategory = BussinessConstant.USER_TYPE_ZY;
                            } else if (DataDictionaryConstant.SHIPPER_TYPE_GYS.equals(tmsShipbillHeaderModel.getShipperType())) {
                                userCategory = BussinessConstant.USER_TYPE_GYS;
                            }
                            allNoticeUser.addAll(userProxy.getEnterpriseUsers(messageConfigDTO.getEnterpriseId().toString(), userCategory, tmsShipbillHeaderModel.getShipperId().toString()));
                        });
                    }
                    if (DataDictionaryConstant.NOTICE_TO_Y.equals(messageConfigDTO.getNoticeConsignee())){
                        tmsShipbillHeaderModelList.stream().forEach(tmsShipbillHeaderModel -> {
                            String userCategory = StrUtil.EMPTY;
                            if (DataDictionaryConstant.CONSIGNEE_TYPE_KH.equals(tmsShipbillHeaderModel.getConsigneeType())) {
                                userCategory = BussinessConstant.USER_TYPE_KH;
                            } else if (DataDictionaryConstant.CONSIGNEE_TYPE_CK.equals(tmsShipbillHeaderModel.getConsigneeType())) {
                                userCategory = BussinessConstant.USER_TYPE_ZY;
                            } else if (DataDictionaryConstant.CONSIGNEE_TYPE_GYS.equals(tmsShipbillHeaderModel.getConsigneeType())) {
                                userCategory = BussinessConstant.USER_TYPE_GYS;
                            }
                            allNoticeUser.addAll(userProxy.getEnterpriseUsers(messageConfigDTO.getEnterpriseId().toString(), userCategory, tmsShipbillHeaderModel.getConsigneeId().toString()));
                        });
                    }
                }
            }
        }
        if (CollectionUtil.isNotEmpty(allNoticeUser)) {
            channelMessageUserDTOList = convertChannelMessageUser(allNoticeUser);
        }
        log.info("topic={},title={},channelMessageUserDTOList={}", TOPIC, "buildChannelMessageUserDTO", JSON.toJSONString(channelMessageUserDTOList));
        return channelMessageUserDTOList;
    }

    /**
     * user转换
     * @param users
     * @return
     */
    private List<ChannelMessageUserDTO> convertChannelMessageUser(List<User> users) {
        users = Lists.newArrayList(users.stream().collect(Collectors.toMap(User::getId, t2 -> t2, (t1, t2) -> t2)).values());
        return users.stream().map(user -> {
            ChannelMessageUserDTO channelMessageUserDTO = new ChannelMessageUserDTO();
            channelMessageUserDTO.setUserId(Long.valueOf(user.getId()));
            channelMessageUserDTO.setUserName(user.getUsername());
            channelMessageUserDTO.setNickName(user.getNickname());
            List<Organization> organizationList = Lists.newArrayList();
            try {
                organizationList = userProxy.getDepartmentByUserId(user.getId());
            } catch (Exception e) {
                log.warn("topic={},title={},部门查询异常", TOPIC, "convertChannelMessageUser", e);
            }
            if (CollectionUtil.isNotEmpty(organizationList)) {
                channelMessageUserDTO.setDepartmentName(organizationList.get(0).getName());
            }
            channelMessageUserDTO.setPhone(user.getPhoneNumber());
            channelMessageUserDTO.setEmail(user.getEmailAddr());
            return channelMessageUserDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 获取替换key
     * @param messageOrderTypeEnum
     * @return
     */
    private String getKey(MessageOrderTypeEnum messageOrderTypeEnum) {
        return "${"+messageOrderTypeEnum.getDesc()+"}";
    }

    /**
     * 构建消息内容
     * @param content
     * @param billCodeMap
     * @return
     */
    private String buildContent(String content, Map<String, String> billCodeMap) {
        final String[] resultContent = {content};
        Arrays.stream(MessageOrderTypeEnum.values()).forEach(messageOrderTypeEnum ->
                resultContent[0] = resultContent[0].replace(getKey(messageOrderTypeEnum),
                        billCodeMap.getOrDefault(getKey(messageOrderTypeEnum), StrUtil.EMPTY)));
        return resultContent[0];
    }

    /**
     * 构建billCodeMap
     * @param sendMessageDTO
     * @param billCodeMap
     * @return
     */
    private List<TmsShipbillHeaderModel> buildBillCodeMapAndReturnShipBill(SendMessageDTO sendMessageDTO,
                                                                           Map<String, String> billCodeMap) {
        List<String> shipBillIdList = sendMessageDTO.getBillCode();
        Criteria criteria;
        Restriction restriction;
        if (MessageOrderTypeEnum.LOADING_NO.getCode().equals(sendMessageDTO.getMessageOrderType())) {
            billCodeMap.put(getKey(MessageOrderTypeEnum.LOADING_NO), sendMessageDTO.getBillCode().stream()
                    .filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
            criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
            restriction = new RestrictionBuilder()
                    .in("loadingBillId",sendMessageDTO.getBillCode().toArray(new String[0]))
                    .build();
            criteria.setRestriction(restriction);
            List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
            shipBillIdList = tmsLoadingBillDetailModelList.stream()
                    .map(TmsLoadingBillDetailModel::getShipbillId).filter(StrUtil::isNotBlank).distinct()
                    .collect(Collectors.toList());
        } else if (MessageOrderTypeEnum.APPOINTMENT_NO.getCode().equals(sendMessageDTO.getMessageOrderType())) {
            billCodeMap.put(getKey(MessageOrderTypeEnum.APPOINTMENT_NO), sendMessageDTO.getBillCode().stream()
                    .filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
            criteria = Criteria.forClass(TmsAppointmentDetailModel.class);
            restriction = new RestrictionBuilder()
                    .in("appointmentId",sendMessageDTO.getBillCode().toArray(new String[0]))
                    .build();
            criteria.setRestriction(restriction);
            List<TmsAppointmentDetailModel> tmsAppointmentDetailModelList = tmsAppointmentDetailMapper.findByCriteria(criteria);
            shipBillIdList = tmsAppointmentDetailModelList.stream()
                    .map(TmsAppointmentDetailModel::getShipbillId).filter(StrUtil::isNotBlank).distinct()
                    .collect(Collectors.toList());
        }
        if (CollectionUtil.isEmpty(shipBillIdList)) {
            throw new BizException("单号异常=" + JSON.toJSONString(sendMessageDTO.getBillCode()));
        }
        List<TmsShipbillHeaderModel> tmsShipbillHeaderModelList = tmsShipbillHeaderMapper.findByIds(TmsShipbillHeaderModel.class,
                shipBillIdList.toArray(new String[0]), null);
        billCodeMap.put(getKey(MessageOrderTypeEnum.SHIP_NO), tmsShipbillHeaderModelList.stream()
                .map(TmsShipbillHeaderModel::getShipbillNo).filter(StrUtil::isNotBlank).distinct()
                .collect(Collectors.joining(",")));
        billCodeMap.put(getKey(MessageOrderTypeEnum.ORDER_NO), tmsShipbillHeaderModelList.stream()
                .map(TmsShipbillHeaderModel::getOrderNo).filter(StrUtil::isNotBlank).distinct()
                .collect(Collectors.joining(",")));
        billCodeMap.put(getKey(MessageOrderTypeEnum.WMS_NO), tmsShipbillHeaderModelList.stream()
                .map(TmsShipbillHeaderModel::getWmsOrderNo).filter(StrUtil::isNotBlank).distinct()
                .collect(Collectors.joining(",")));
        if (!billCodeMap.containsKey(getKey(MessageOrderTypeEnum.LOADING_NO))) {
            setLoadingNo(shipBillIdList, billCodeMap);
        }
        if (!billCodeMap.containsKey(getKey(MessageOrderTypeEnum.APPOINTMENT_NO))) {
            setAppointmentNo(shipBillIdList, billCodeMap);
        }
        log.info("topic={},title={},billCodeMap={}", TOPIC, "buildBillCodeMapAndReturnShipBill", JSON.toJSONString(billCodeMap));
        return tmsShipbillHeaderModelList;
    }

    /**
     * 设置派车单号
     * @param shipBillIdList
     * @param billCodeMap
     */
    private void setLoadingNo(List<String> shipBillIdList, Map<String, String> billCodeMap) {
        Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
        Restriction restriction = new RestrictionBuilder()
                .in("shipbillId",shipBillIdList.toArray(new String[0]))
                .build();
        criteria.setRestriction(restriction);
        List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(tmsLoadingBillDetailModelList)) {
            billCodeMap.put(getKey(MessageOrderTypeEnum.LOADING_NO), StrUtil.EMPTY);
        } else {
            Map<String, String> idMaps = tmsLoadingBillDetailModelList.stream()
                    .sorted(Comparator.comparing(TmsLoadingBillDetailModel::getCreatetime))
                    .collect(Collectors.toMap(t1 -> t1.getShipbillId(), t2 -> t2.getLoadingBillId(), (t1, t2) -> t2));
            billCodeMap.put(getKey(MessageOrderTypeEnum.LOADING_NO), idMaps.values().stream()
                    .filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
        }
    }

    /**
     * 设置预约单号
     * @param shipBillIdList
     * @param billCodeMap
     */
    private void setAppointmentNo(List<String> shipBillIdList, Map<String, String> billCodeMap) {
        Criteria criteria = Criteria.forClass(TmsAppointmentDetailModel.class);
        Restriction restriction = new RestrictionBuilder()
                .in("shipbillId",shipBillIdList.toArray(new String[0]))
                .build();
        criteria.setRestriction(restriction);
        List<TmsAppointmentDetailModel> tmsAppointmentDetailModelList = tmsAppointmentDetailMapper.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(tmsAppointmentDetailModelList)) {
            billCodeMap.put(getKey(MessageOrderTypeEnum.APPOINTMENT_NO), StrUtil.EMPTY);
        } else {
            Map<String, String> idMaps = tmsAppointmentDetailModelList.stream()
                    .sorted(Comparator.comparing(TmsAppointmentDetailModel::getCreatetime))
                    .collect(Collectors.toMap(t1 -> t1.getShipbillId(), t2 -> t2.getAppointmentId(), (t1, t2) -> t2));
            List<TmsAppointmentHeaderModel> tmsAppointmentHeaderModelList = tmsAppointmentHeaderMapper.findByIds(
                    TmsAppointmentHeaderModel.class, idMaps.values().toArray(new String[0]), null);
            billCodeMap.put(getKey(MessageOrderTypeEnum.APPOINTMENT_NO), tmsAppointmentHeaderModelList.stream()
                    .filter(tmsAppointmentHeaderModel -> !DataDictionaryConstant.APPOINTMENT_STATUS_QX.equals(tmsAppointmentHeaderModel.getStatus()))
                    .map(TmsAppointmentHeaderModel::getAppointmentNo).filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
        }
    }

    /**
     * 运单匹配条件
     * @param tmsShipbillHeaderModelList
     * @param configConditionDTOList
     * @return
     */
    private Boolean shipBillMatchCondition(List<TmsShipbillHeaderModel> tmsShipbillHeaderModelList, List<MessageConfigConditionDTO> configConditionDTOList) {
        Boolean result = Boolean.TRUE;
        if (CollectionUtil.isNotEmpty(configConditionDTOList)) {
            result = tmsShipbillHeaderModelList.stream().anyMatch(tmsShipbillHeaderModel ->
                    matchCondition(tmsShipbillHeaderModel, configConditionDTOList));
        }
        log.info("topic={},title={},result={},tmsShipbillHeaderModelList={},configConditionDTOList={}", TOPIC, "shipBillMatchCondition",result,
                JSON.toJSONString(tmsShipbillHeaderModelList), JSON.toJSONString(configConditionDTOList));
        return result;
    }

    /**
     * 条件匹配
     * @param tmsShipbillHeaderModel
     * @param configConditionDTOList
     * @return
     */
    private Boolean matchCondition(TmsShipbillHeaderModel tmsShipbillHeaderModel, List<MessageConfigConditionDTO> configConditionDTOList) {
        Boolean result = Boolean.TRUE;
        if (CollectionUtil.isNotEmpty(configConditionDTOList)) {
            result = configConditionDTOList.stream().allMatch(configConditionDTO ->
                    singleMatchCondition(tmsShipbillHeaderModel, configConditionDTO));
        }
        log.info("topic={},title={},result={},tmsShipbillHeaderModel={},configConditionDTOList={}", TOPIC, "matchCondition",result,
                JSON.toJSONString(tmsShipbillHeaderModel), JSON.toJSONString(configConditionDTOList));
        return result;
    }

    /**
     * 单个条件匹配
     * @param tmsShipbillHeaderModel
     * @param configConditionDTO
     * @return
     */
    private Boolean singleMatchCondition(TmsShipbillHeaderModel tmsShipbillHeaderModel, MessageConfigConditionDTO configConditionDTO) {
        boolean result = Boolean.TRUE;
        switch (MessageConfigConditionEnum.getByCode(configConditionDTO.getConditionType())) {
            case DELIVERY_METHOD_TYPE :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getDeliveryMethodType())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getDeliveryMethodType().toString());
                }
                break;
            case SHIPPER_TYPE :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getShipperType())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getShipperType().toString())
                            && configConditionDTO.getUnitId().contains(tmsShipbillHeaderModel.getShipperUnitId().toString());
                }
                break;
            case CONSIGNEE_TYPE :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getConsigneeType())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getConsigneeType().toString())
                            && configConditionDTO.getUnitId().contains(tmsShipbillHeaderModel.getConsigneeUnitId().toString());
                }
                break;
            case ORDER_TYPE :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getOrderType())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getOrderType().toString());
                }
                break;
            case ORDER_BUSINESS_TYPE :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getOrderBusinessType())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getOrderBusinessType().toString());
                }
                break;
            case TRANSPORT_TYPE :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getTransportType())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getTransportType().toString());
                }
                break;
            case TEMPERATURE_REQUIREMENT :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getTemperatureRequirement())) {
                    result = false;
                } else {
                    result = configConditionDTO.getConditionValue().equals(tmsShipbillHeaderModel.getTemperatureRequirement().toString());
                }
                break;
            case CARGO_OWNER :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getCargoOwnerId())) {
                    result = false;
                } else {
                    result = configConditionDTO.getUnitId().contains(tmsShipbillHeaderModel.getCargoOwnerId().toString());
                }
                break;
            case DEPARTMENT :
                if (ObjectUtil.isNull(tmsShipbillHeaderModel.getDepartmentId())) {
                    result = false;
                } else {
                    result = configConditionDTO.getUnitId().contains(tmsShipbillHeaderModel.getDepartmentId());
                }
                break;
            default:
                break;
        }
        log.info("topic={},title={},result={},tmsShipbillHeaderModel={},configConditionDTO={}", TOPIC, "singleMatchCondition",result,
                JSON.toJSONString(tmsShipbillHeaderModel), JSON.toJSONString(configConditionDTO));
        return result;
    }

    /**
     * getMessageConfig
     * @param vo
     * @param alarmType
     * @return
     */
    private TmsMessageConfigModel getMessageConfig(MessageJobVO vo, String alarmType) {
        Criteria criteria = Criteria.forClass(TmsMessageConfigModel.class);
        Restriction restriction = new RestrictionBuilder()
                .eq("type", alarmType)
                .eq("status", MessageConfigStatusEnum.ENABLE.getCode())
                .eq("enterpriseId",vo.getEnterpriseId())
                .build();
        criteria.setRestriction(restriction);
        List<TmsMessageConfigModel> messageConfigModelList = tmsMessageConfigMapper.findByCriteria(criteria);
        if (CollectionUtil.isNotEmpty(messageConfigModelList)) {
            return messageConfigModelList.get(0);
        }
        return null;
    }

    /**
     * getMatchShipBill
     * @param vo
     * @param statusList
     * @return
     */
    private List<TmsShipbillHeaderModel> getMatchShipBill(MessageJobVO vo, List<String> statusList) {
        Criteria criteria = Criteria.forClass(TmsShipbillHeaderModel.class);
        Restriction restriction = new RestrictionBuilder()
                .in(TmsShipbillHeaderModel::getStatus, statusList)
                .eq("enterpriseId",vo.getEnterpriseId())
                .build();
        criteria.setRestriction(restriction);
        List<TmsShipbillHeaderModel> shipbillHeaderModelList = tmsShipbillHeaderMapper.findByCriteria(criteria);
        return shipbillHeaderModelList;
    }

    /**
     * sendShipBillMessage
     * @param shipbillHeaderModelList
     * @param vo
     * @param alarmType
     */
    private void sendShipBillMessage(List<TmsShipbillHeaderModel> shipbillHeaderModelList, MessageJobVO vo, String alarmType) {
        shipbillHeaderModelList.forEach(shipbillHeaderModel -> {
            SendMessageDTO sendMessageDTO = new SendMessageDTO();
            sendMessageDTO.setMessageOrderType(MessageOrderTypeEnum.SHIP_NO.getCode());
            sendMessageDTO.setMessageType(alarmType);
            sendMessageDTO.setBillCode(Lists.newArrayList(shipbillHeaderModel.getShipbillId()));
            sendMessageDTO.setUser(generateUser(vo));
            send(sendMessageDTO);
        });
    }

    /**
     * getOffsetDate
     * @param date
     * @param offset
     * @param offsetUnit
     * @return
     */
    private Date getOffsetDate(Date date, Integer offset, String offsetUnit) {
        if (MessageTimeUnitEnum.SECOND.getCode().equals(offsetUnit)) {
            return DateUtil.offsetSecond(date, offset);
        }
        if (MessageTimeUnitEnum.MINUTE.getCode().equals(offsetUnit)) {
            return DateUtil.offsetMinute(date, offset);
        }
        if (MessageTimeUnitEnum.HOUR.getCode().equals(offsetUnit)) {
            return DateUtil.offsetHour(date, offset);
        }
        if (MessageTimeUnitEnum.DAY.getCode().equals(offsetUnit)) {
            return DateUtil.offsetDay(date, offset);
        }
        return date;
    }

    /**
     * interval
     * @param interval
     * @param intervalUnit
     * @return
     */
    private Integer getAlarmInterval(Integer interval, String intervalUnit) {
        if (MessageTimeUnitEnum.SECOND.getCode().equals(intervalUnit)) {
            return interval;
        }
        if (MessageTimeUnitEnum.MINUTE.getCode().equals(intervalUnit)) {
            return interval * 60;
        }
        if (MessageTimeUnitEnum.HOUR.getCode().equals(intervalUnit)) {
            return interval * 60 * 60;
        }
        if (MessageTimeUnitEnum.DAY.getCode().equals(intervalUnit)) {
            return interval * 60 * 60 * 24;
        }
        return interval;
    }

    /**
     * generateUser
     * @param vo
     * @return
     */
    private UserEntity generateUser(MessageJobVO vo) {
        UserEntity user = new UserEntity();
        user.setNickname("系统");
        user.setEnterpriseId(vo.getEnterpriseId());
        user.setEnterpriseName("系统");
        return user;
    }

    /**
     * intervalCompare
     * @param title
     * @param interval
     * @param lastMessage
     * @return
     */
    private boolean intervalCompare(String title, Integer interval, TmsMessageModel lastMessage) {
        log.info("{} lastMessage={}", title, JSON.toJSONString(lastMessage));
        if (ObjectUtil.isNotNull(lastMessage)) {
            if (DateUtil.between(lastMessage.getSendTime(), DateUtil.date(), DateUnit.SECOND) >= interval) {
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        } else {
            return Boolean.TRUE;
        }
    }

    /**
     * getShipBillDetail
     * @param vo
     * @param shipbillId
     * @return
     */
    private List<TmsShipbillDetailModel> getShipBillDetail(MessageJobVO vo, String shipbillId) {
        Criteria criteria = Criteria.forClass(TmsShipbillDetailModel.class);
        Restriction restriction = new RestrictionBuilder()
                .eq(TmsShipbillDetailModel::getShipbillId, shipbillId)
                .eq("enterpriseId",vo.getEnterpriseId())
                .build();
        criteria.setRestriction(restriction);
        return tmsShipbillDetailMapper.findByCriteria(criteria);
    }
}
