package com.zd.chemical.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.zd.chemical.controller.HxpAIOController;
import com.zd.chemical.domain.*;
import com.zd.chemical.domain.vo.*;
import com.zd.chemical.mapper.*;
import com.zd.chemical.properties.AlarmProperties;
import com.zd.chemical.service.*;
import com.zd.chemical.util.SmsSydUtil;
import com.zd.common.core.domain.R;
import com.zd.common.core.domain.per.PerPrefix;
import com.zd.common.core.exception.ServiceException;
import com.zd.common.core.utils.DateUtils;
import com.zd.common.core.utils.SecurityUtils;
import com.zd.common.core.web.domain.AjaxResult;
import com.zd.common.datascope.annotation.DataScope;
import com.zd.common.security.utils.DictUtils;
import com.zd.common.security.utils.SaveUtil;
import com.zd.system.api.alarm.RemoteAlarmService;
import com.zd.system.api.alarm.domain.AlarmEntrty;
import com.zd.system.api.alarm.domain.Routes;
import com.zd.system.api.domain.InventoryTag;
import com.zd.system.api.domain.SysDictData;
import com.zd.system.api.domain.SysFile;
import com.zd.system.api.forward.RemoteForwardService;
import com.zd.system.api.laboratory.RemoteLaboratoryService;
import com.zd.system.api.laboratory.RemoteMessageContentService;
import com.zd.system.api.laboratory.domain.RemoteLabHardware;
import com.zd.system.api.netty.RemoteNettyService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 库存管理Service业务层处理
 *
 * @author liubo
 * @date 2022-06-17
 */
@Service
public class HxpStockServiceImpl implements IHxpStockService {
    private static Logger logger = LoggerFactory.getLogger(HxpStockServiceImpl.class);

    private static Map<String, Date> cacheMap = new ConcurrentHashMap<>();

    private static int interval = 60 * 3;

    @Value("${config.interval:180}")
    private void setInterval(Integer interval){
        HxpStockServiceImpl.interval = interval;
    }

    public static Integer phoneMode = 0;

    @Value("${phoneMode:0}")
    private void setPhoneMode(Integer phoneMode){
        HxpStockServiceImpl.phoneMode = phoneMode;
    }

    @Autowired
    private HxpStockMapper hxpStockMapper;
    @Autowired
    private HxpChemicalJoinCabinetMapper hxpChemicalJoinCabinetMapper;
    @Autowired
    private HxpUserecordMapper hxpUserecordMapper;
    @Autowired
    private HxpAlarmConfigMapper hxpAlarmConfigMapper;
    @Autowired
    private HxpAlarmRecordMapper hxpAlarmRecordMapper;
    @Autowired
    private HxpClassifyConfigMapper hxpClassifyConfigMapper;
    @Autowired
    private HxpSmartTerminalMapper hxpSmartTerminalMapper;
    @Autowired
    private RemoteMessageContentService remoteMessageContentService;
    @Autowired
    private RemoteLaboratoryService remoteLaboratoryService;
    @Autowired
    private IHxpUserecordService hxpUserecordService;
    @Autowired
    private IHxpChemicalJoinCabinetService hxpCabinetJoinCabinetService;
    @Autowired
    private IHxpClassifyConfigService hxpClassifyConfigService;
    @Autowired
    private RemoteAlarmService remoteAlarmService;
    @Autowired
    private HxpCabinetlockLogMapper hxpCabinetlockLogMapper;
    @Resource
    private RemoteNettyService remoteNettyService;
    @Resource
    private SmsSydUtil smsSydUtil;

    @Resource
    private AlarmProperties alarmProperties;
    @Resource
    private RemoteForwardService remoteForwardService;
    /**
     * 查询库存管理
     *
     * @param id 库存管理主键
     * @return 库存管理
     */
    @Override
    public HxpStock selectHxpStockById(Long id) {
        return hxpStockMapper.selectHxpStockById(id);
    }

    /**
     * 查询库存管理列表
     *
     * @param hxpStock 库存管理
     * @return 库存管理
     */
    @Override
    public List<HxpStock> selectHxpStockList(HxpStock hxpStock) {
        List<HxpStock> list = hxpStockMapper.selectHxpStockList(hxpStock);
        List<SysDictData> proDictDatas = DictUtils.getDictCache("chemical_shape");

        list.forEach(a -> {
            if(StringUtils.isNotBlank(a.getSafeUserId())){
                a.setSafeUserName(hxpChemicalJoinCabinetMapper.queryUserNameBySafeUserId(a.getSafeUserId()));
            }
            if(a.getChemicalClassify() != null){
                a.setClassifyConfig(hxpClassifyConfigMapper.selectHxpClassifyConfigById(a.getChemicalClassify()));
            }

            for(SysDictData dictData : proDictDatas){
                if(dictData.getDictValue().equals(a.getChemicalShape()+"")){
                    a.setChemicalShapeName(dictData.getDictLabel());
                }
            }
            // 计算库存净重
            a.setSuttle(a.getOutUsages().subtract(Optional.ofNullable(a.getTare()).orElse(BigDecimal.ZERO)));
        });
        return list;
    }

    /**
     * 查询库存管理列表
     *
     * @param hxpStockSearch 库存管理
     * @return 库存管理
     */
    @Override
    @DataScope(deptAlias = "st", permi = PerPrefix.HXP_STOCKDETAIL)
    public List<HxpStockDetailVO> selectHxpStockListDetail(HxpStockSearch hxpStockSearch) {
        List<HxpStockDetailVO> list = hxpStockMapper.selectHxpStockListDetail(hxpStockSearch);
        return list;
    }

    /**
     * 查询库存管理列表
     *
     * @param hxpStockSearch 库存管理
     * @return 库存管理
     */
    @Override
    @DataScope(deptAlias = "st", permi = PerPrefix.HXP_STOCKJOIN)
    public List<HxpStockJoinVO> selectHxpStockListJoin(HxpStockSearch hxpStockSearch) {
        List<HxpStockJoinVO> list = hxpStockMapper.selectHxpStockListJoin(hxpStockSearch);
        return list;
    }

    /**
     * 查询库存管理列表
     *
     * @param hxpStockSearch 库存管理
     * @return 库存管理
     */
    @Override
    @DataScope(deptAlias = "st", permi = PerPrefix.HXP_STOCKOUT)
    public List<HxpStockOutVO> selectHxpStockListOut(HxpStockSearch hxpStockSearch) {
        List<HxpStockOutVO> list = hxpStockMapper.selectHxpStockListOut(hxpStockSearch);
        return list;
    }

    /**
     * 新增库存管理
     *
     * @param hxpStock 库存管理
     * @return 结果
     */
    @Override
    @Transactional
    public HxpStock insertHxpStock(HxpStock hxpStock) {

        logger.info("化学品入库，前端参数：" + JSONUtil.toJsonStr(hxpStock));

        if(hxpStock.getUsages().compareTo(hxpStock.getTare()) <= 0){
            throw new ServiceException("入库重量错误，入库失败！");
        }

        HxpClassifyConfig hxpClassifyConfig = hxpClassifyConfigMapper.selectHxpClassifyConfigById(hxpStock.getChemicalClassify());

        // 出于数据安全考虑，前端获取并回传的数据应该后端再校验一次，暂记录
        if(hxpClassifyConfig.getLabelType() == 1 && StringUtils.isBlank(hxpStock.getRfidCode())){
            throw new ServiceException("该化学品必须绑定RFID标签，请先识别帖瓶！");
        }

        if(hxpClassifyConfig != null && hxpClassifyConfig.getJoinStatus() == 2){
            //  1. 双人验证设置功能校验 功能需求确认
            if((hxpStock.getJoinOneUser() == null || hxpStock.getJoinTwoUser() == null)){// hxpStock.getVerification() == 2 &&
                throw new ServiceException("必须要双人验证成功才能入库！");
            }
        }

        if(StringUtils.isNotBlank(hxpStock.getRfidCode()) && selectCountByRfidCode(hxpStock) > 0){
            throw new ServiceException("该标签已绑定，请扫描新的RFID标签！");
        }

        if(hxpStock.getJoinOneUser() == null){
            hxpStock.setJoinOneUser(SecurityUtils.getUserId());
        }

        hxpStock.setPrintCode(hxpClassifyConfig.getPrintCode());
        hxpStock.setTagCode(HxpAIOController.genTagCode());
        if(hxpStockMapper.selectCountByTagCode(hxpStock.getTagCode()) > 0){
            // 未避免编号重复，此处添加校验一次重新获取
            hxpStock.setTagCode(HxpAIOController.genTagCode());
        }

        //设置其他公共字段
        SaveUtil.setCommonAttr(hxpStock);
        hxpStock.setJoinUserId(SecurityUtils.getUserIdEx());
        hxpStock.setJoinTime(DateUtils.getNowDate());
        //初始化库存量
        hxpStock.setOutUsages(hxpStock.getUsages());
        hxpStock.setStatus(1);
        hxpStockMapper.insertHxpStock(hxpStock);

        // 入库成功修改机柜化学品关联状态
        HxpChemicalJoinCabinet hxpCabinetJoinCabinet = new HxpChemicalJoinCabinet();
        hxpCabinetJoinCabinet.setId(hxpStock.getJoinId());
        hxpCabinetJoinCabinet.setStatus(1);
        hxpChemicalJoinCabinetMapper.updateHxpChemicalJoinCabinet(hxpCabinetJoinCabinet);

        List<SysDictData> proDictDatas = DictUtils.getDictCache("chemical_shape");
        for(SysDictData dictData : proDictDatas){
            if(dictData.getDictValue().equals(hxpStock.getChemicalShape()+"")){
                hxpStock.setChemicalShapeName(dictData.getDictLabel());
                break;
            }
        }

        hxpStock.setSuttle(hxpStock.getOutUsages().subtract(Optional.ofNullable(hxpStock.getTare()).orElse(BigDecimal.ZERO)));

        if(hxpStock.getLockLogId() != null){
            HxpCabinetlockLog hxpCabinetlockLog = new HxpCabinetlockLog();
            hxpCabinetlockLog.setId(hxpStock.getLockLogId());
            hxpCabinetlockLog.setStockId(hxpStock.getId());
            hxpCabinetlockLogMapper.updateHxpCabinetlockLog(hxpCabinetlockLog);
        }

        return hxpStock;
    }


    /**
     * 修改库存管理
     *
     * @param hxpStock 库存管理
     * @return 结果
     */
    @Override
    public int updateHxpStock(HxpStock hxpStock) {
        // 应该校验 标签编号是否已经绑定
        if(StringUtils.isNotBlank(hxpStock.getRfidCode()) && selectCountByRfidCode(hxpStock) > 0){
            throw new ServiceException("该标签已绑定，请扫描新的RFID标签！");
        }
        hxpStock.setUpdateTime(DateUtils.getNowDate());
        hxpStock.setUpdateBy(SecurityUtils.getUsername());
        hxpStock.setChemicalShape(null);
        int count = hxpStockMapper.updateHxpStock(hxpStock);

        return count;
    }

    /**
     * 批量删除库存管理
     *
     * @param ids 需要删除的库存管理主键
     * @return 结果
     */
    @Override
    public int deleteHxpStockByIds(Long[] ids) {
        return hxpStockMapper.deleteHxpStockByIds(ids);
    }

    /**
     * 删除库存管理信息
     *
     * @param id 库存管理主键
     * @return 结果
     */
    @Override
    public int deleteHxpStockById(Long id) {
        return hxpStockMapper.deleteHxpStockById(id);
    }

    /**
     * RFID 实时检测 是否是违规带离实验室
     * @return
     */
    @Override
    public synchronized boolean RFIDCheck(InventoryTag tag) {
        String rfidCode = tag.getEpc();
        if(StringUtils.isBlank(rfidCode)){
            return false;
        }
        Date d = cacheMap.get(rfidCode);
        if(d != null && DateUtil.compare(DateUtil.offsetSecond(d, interval), DateUtils.getNowDate()) > 0){
            return false;
        }


        logger.info("RFID 实时检测 RFIDCheck（标签编号）: " + rfidCode);
        HxpStock hxpStock = hxpStockMapper.selectByRfidCode(rfidCode);
        if(hxpStock == null){
            return false;
        }

        // 查询该库存数据是否处于领用状态
        HxpUserecord hxpUserecord = hxpUserecordMapper.selectByStockId(hxpStock.getId());
        if(hxpUserecord != null){
            logger.info("RFID 化学品正常使用中: " + JSONUtil.toJsonStr(hxpUserecord));
            return false;
        }else {
            logger.error("RFID 检测到违规触发报警: " + JSONUtil.toJsonStr(hxpStock));
            String streamUrl = alarmProperties.getStreamUrl();
            R<SysFile> fileR = null;
            if (org.springframework.util.StringUtils.hasLength(streamUrl)){
                fileR= remoteForwardService.photograph(alarmProperties.getStreamUrl());
            }
            if (fileR!=null){
                logger.info("文件上传状态：{}，接口返回消息：{}，文件上传路径：{}",fileR.getCode(),fileR.getMsg(),fileR.getData());
            }
            //触发RFID警报
            RemoteLabHardware hardware = tag.getRemoteLabHardware();
            boolean isAlarm = false;
            if (hardware!=null){
                R<Boolean> alarm = remoteNettyService.alarm(hardware);//RFID设备报警
                logger.info("==================>{},{}",alarm.getCode(),alarm.getMsg());
                //isAlarm = true;
            }else {
                logger.info("==================> rfid 参数有误！"+ tag.toString());
            }
            // 如果非领用状态，做报警台账
            // 0.检测实验室声光报警器是否使用- 使用则直接调用触发- 否则跳过
            Map<String,Object> subInfo = hxpUserecordMapper.selectSubInfoById(hxpStock.getSubId());
            String subName = "";
            String safeUserId = "";
            if(subInfo != null){
                subName = subInfo.get("name")==null?"":String.valueOf(subInfo.get("name"));
                safeUserId = subInfo.get("safeUserId")==null?"":String.valueOf(subInfo.get("safeUserId"));
            }

            String terminalNum = null;
            Integer dealTime = 0;
            List<Map<String, Object>> terminalList = hxpSmartTerminalMapper.selectTerminalBySubId(8, hxpStock.getSubId());
            if(CollectionUtils.isEmpty(terminalList)){
                logger.error("实验室【"+subName+"】ID" + hxpStock.getSubId() +"未设置或启用声光报警器！");
            }else {
                Map<String, Object> smartTerminal = terminalList.get(0);
                terminalNum = String.valueOf(smartTerminal.get("hardwareNum"));
                dealTime = (Integer) smartTerminal.get("dealTime");
                // 执行声光报警器动作触发
                remoteLaboratoryService.controlByInside(Long.parseLong(smartTerminal.get("id")+"") , "01");
                isAlarm = true;
                // 控制响铃时长
                if(smartTerminal.get("ringTime") != null){
                    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
                    executorService.schedule(new Runnable() {
                        @Override
                        public void run() {
                            remoteLaboratoryService.controlByInside(Long.parseLong(smartTerminal.get("id")+"") , "00");
                        }
                    }, Long.parseLong(smartTerminal.get("ringTime") + ""), TimeUnit.SECONDS);
                }
            }

            HxpAlarmRecord hxpAlarmRecord;
            if(isAlarm){
                // 默认一个实验室只触发一个报警器
                hxpAlarmRecord = new HxpAlarmRecord();
                hxpAlarmRecord.setAlarmContent("未领用即携带化学品离开实验室【"+subName+"】，" + "化学品（"+hxpStock.getChemicalName()+"）, 请尽快确认！");
                hxpAlarmRecord.setAlarmType(2);
                hxpAlarmRecord.setHasValid(1);
                hxpAlarmRecord.setAlarmMode(2);
                hxpAlarmRecord.setAlarmTime(DateUtils.getNowDate());
                hxpAlarmRecord.setSubId(hxpStock.getSubId());
                hxpAlarmRecord.setTerminalNum(terminalNum == null ? tag.getSerialNumber() : terminalNum);
                hxpAlarmRecord.setHandlingStatus(1);
                // TODO 请在此处新增图片路径字段并使用 fileR 中的返回值url作为图片路径以供前端调用，具体实现方式可参考 com.zd.bottle.service.impl.AlarmRecordServiceImpl.remoteAdd#155 行代码,默认配置为空，具体配置可参考zd-bottle-dev.yml#113行到115行

                hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);
            }

            // 报警通知演示临时通知给实验室管理员  phones
            Long recordId = sendPhoneAlarm(hxpStock.getId(),hxpStock.getSubId(), subName, hxpStock.getChemicalName(), subInfo.get("phones") + "");

            cacheMap.put(rfidCode, DateUtils.getNowDate());

            // 系统通知 未领用即携带化学品离开实验室-实验室安全责任人
            Map<String, Object> msgData = new HashMap<>();
            msgData.put("sendRange", 3);
            msgData.put("messClass", -1);
            msgData.put("content", "系统检测到：化学品【" + hxpStock.getChemicalName() + "】，未领用被带离实验室【"+subName+"】，请您确认！");

            List<Map<String, Object>> userMsgList = new ArrayList<>();

            if(StringUtils.isNotBlank(safeUserId)){
                String[] userIds = safeUserId.split(",");
                Map<String, Object> userMsg;
                for (String userId : userIds) {
                    userMsg = new HashMap<>();
                    userMsg.put("joinUserId", userId);
                    userMsg.put("isRead", false);
                    userMsgList.add(userMsg);
                }
                msgData.put("messageUserList", userMsgList);

                remoteMessageContentService.addDynamicMessage(msgData);
            }

            // 需求变动内容：未领用即携带化学品离开房间报警时，如实验室安全责任人通过化学品终端或PC管理后台操作处理，状态更改为已处理，报警流程终止
            // 保证逻辑严谨，数据必须进行强关联
            if(recordId != null){
                // 1.查询标签所属实验室院系报警配置流程处理
                List<HxpAlarmConfig> hxpAlarmConfigList = hxpAlarmConfigMapper.selectBySubId(3, hxpStock.getSubId());
                // 2.最多五个步骤分别执行
                if(CollectionUtils.isNotEmpty(hxpAlarmConfigList)){
                    logger.error("实验室【"+subName+"】ID" + hxpStock.getSubId() +"执行用户短信通知！");

                    Date date = DateUtil.offsetMinute(DateUtils.getNowDate(), Optional.ofNullable(dealTime).orElse(1));

                    for (HxpAlarmConfig hxpAlarmConfig : hxpAlarmConfigList) {
                        hxpAlarmRecord = new HxpAlarmRecord();
                        hxpAlarmRecord.setAlarmContent("未领用即携带化学品离开实验室【"+subName+"】，" + "化学品（"+hxpStock.getChemicalName()+"）,请尽快确认！");
                        hxpAlarmRecord.setAlarmType(2);
                        hxpAlarmRecord.setAlarmMode(3);
                        hxpAlarmRecord.setHasValid(0);
                        hxpAlarmRecord.setAlarmTime(date);
                        hxpAlarmRecord.setSubId(hxpStock.getSubId());
                        hxpAlarmRecord.setStockId(hxpStock.getId());
                        hxpAlarmRecord.setParentId(recordId);
                        //hxpAlarmRecord.setTerminalNum();
                        hxpAlarmRecord.setHandlingStatus(1);
                        hxpAlarmRecord.setLiableUserIds(hxpAlarmConfig.getAlarmPhone());

                        //执行时间 - 报警时间计算
                        date = DateUtil.offsetMinute(date, Optional.ofNullable(hxpAlarmConfig.getTimeInterval()).orElse(1));
                        // TODO 短信阶梯通知触发流程控制
                        hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);
                    }
                }
            }else {
                logger.error("");
            }

            return true;
        }
    }

    private Long sendPhoneAlarm(Long stockId, Long subId, String subName, String chemicalName, String phones) {

        try {
            String[] to = phones.split(",");
            if(to == null && to.length == 0){
                logger.error("RFID触发电话报警失败：实验室【"+subName+"】管理员未配置手机号！");
                return null;
            }
            to = Arrays.stream(to).distinct().toArray(String[]::new);

            HxpAlarmRecord hxpAlarmRecord = new HxpAlarmRecord();
            hxpAlarmRecord.setAlarmContent("未领用即携带化学品离开实验室【"+subName+"】，" + "化学品（"+chemicalName+"）,请尽快确认！");
            hxpAlarmRecord.setAlarmType(2);
            hxpAlarmRecord.setAlarmMode(3);
            hxpAlarmRecord.setHasValid(1);
            hxpAlarmRecord.setAlarmTime(DateUtils.getNowDate());
            hxpAlarmRecord.setSubId(subId);
            hxpAlarmRecord.setHandlingStatus(1);
            hxpAlarmRecord.setLiableUserIds(phones);
            hxpAlarmRecord.setStockId(stockId);

            hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);

            // 判断四医大还是其他学校短信方案
            String content;
            if(phoneMode == 0){
                /*HxpAlarmRecord hxpAlarmRecord = new HxpAlarmRecord();
                hxpAlarmRecord.setAlarmContent("未领用即携带化学品离开实验室【"+subName+"】，" + "化学品（"+chemicalName+"）,请尽快确认！");
                hxpAlarmRecord.setAlarmType(2);
                hxpAlarmRecord.setAlarmMode(3);
                hxpAlarmRecord.setHasValid(1);
                hxpAlarmRecord.setAlarmTime(DateUtils.getNowDate());
                hxpAlarmRecord.setSubId(subId);
                hxpAlarmRecord.setHandlingStatus(1);
                hxpAlarmRecord.setLiableUserIds(phones);

                hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);*/

                content = "电话报警：" + subName + "的化学品" + chemicalName + "违规带离实验室，请尽快确认！";
                AlarmEntrty alarmEntrty = new AlarmEntrty(Routes.NoticePush, to, content);
                AjaxResult result = remoteAlarmService.send(alarmEntrty);

                logger.error(JSONUtil.toJsonStr(result));
            }else if(phoneMode == 1){
                /*for (String s : to) {
                    HxpAlarmRecord hxpAlarmRecord = new HxpAlarmRecord();
                    hxpAlarmRecord.setAlarmContent("未领用即携带化学品离开实验室【"+subName+"】，" + "化学品（"+chemicalName+"）,请尽快确认！");
                    hxpAlarmRecord.setAlarmType(2);
                    hxpAlarmRecord.setAlarmMode(3);
                    hxpAlarmRecord.setHasValid(1);
                    hxpAlarmRecord.setAlarmTime(DateUtils.getNowDate());
                    hxpAlarmRecord.setSubId(subId);
                    hxpAlarmRecord.setHandlingStatus(1);
                    hxpAlarmRecord.setLiableUserIds(s);

                    hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);
                }*/

                content = "【实验室安全系统】" + subName + "-实验人员未领用即携带化学品离开房间，发生时间："
                        + DateUtil.format(DateUtil.date(), DateUtils.YYYY_MM_DD_HH_MM_SS)
                        + "，请尽快确认。";//短信回复“CL”确认已处理。
                try {
                    smsSydUtil.sendSydSms(content, 1, null, to);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            return hxpAlarmRecord.getId();
        }catch (Exception e){
            e.printStackTrace();
            logger.error("【"+subName+"】RFID触发报警器进行电话通知失败：" + e.getMessage());
            return null;
        }


    }

    @Override
    public int selectCountByRfidCode(HxpStock hxpStock) {
        return hxpStockMapper.selectCountByRfidCode(hxpStock);
    }

    @Override
    public void expireCheck() {

        // 化学品即将过期、已过期-实验室安全责任人  通知功能

        List<HxpStockVO> list = hxpStockMapper.selectStockByExpired();
        if(list.size() > 0){
            List<HxpStockVO> wasExpirelist = new ArrayList<>();
            List<Long> stockIds = new ArrayList<>();
            List<Long> joinIds = new ArrayList<>();
            Map<Long, String> subMsg = new HashMap<>();
            Map<Long, String> subNameMap = new HashMap<>();
            for (HxpStockVO hxpStock : list) {
                if(hxpStock.getExpireStatus()==1){//处理快过期的化学品
                    wasExpirelist.add(hxpStock);
                }else if(hxpStock.getExpireStatus()==2){ //处理过期的化学品
                    stockIds.add(hxpStock.getId());
                    joinIds.add(hxpStock.getJoinId());

                    subMsg.put(hxpStock.getSubId(), subMsg.get(hxpStock.getSubId()) == null ? "" : subMsg.get(hxpStock.getSubId())+"，" + hxpStock.getChemicalName());
                    subNameMap.put(hxpStock.getSubId(),hxpStock.getSubName());
                    // 报警记录
                    HxpAlarmRecord hxpAlarmRecord = new HxpAlarmRecord();
                    hxpAlarmRecord.setAlarmContent(hxpStock.getSubName()+"实验室，化学品（"+hxpStock.getChemicalName() + "）已过期，请尽快确认处理。");
                    hxpAlarmRecord.setAlarmType(1);
                    hxpAlarmRecord.setHasValid(1);
                    hxpAlarmRecord.setAlarmMode(1);
                    hxpAlarmRecord.setAlarmTime(DateUtils.getNowDate());
                    hxpAlarmRecord.setSubId(hxpStock.getSubId());
                    hxpAlarmRecord.setHandlingStatus(1);
                    hxpAlarmRecord.setStockId(hxpStock.getId());
                    hxpAlarmRecord.setLiableUserIds(hxpStock.getSafeUserId());

                    hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);
                }

            }
            //快过期list有数据需要单独处理
            if(wasExpirelist.size()>0){
                wasExpire(wasExpirelist);
            }
            if(stockIds.size() > 0){
                hxpStockMapper.updateExpiredByIds(stockIds);
            }
            if(joinIds.size() > 0){
                hxpChemicalJoinCabinetMapper.updateExpiredByIds(joinIds);
            }
            hxpChemicalJoinCabinetMapper.updateChemicalJoinCabinetByExpired();

            subMsg.forEach((k,v) -> {
                Map<String, Object> subMsgData = new HashMap<>();
                subMsgData.put("sendRange", 3);
                subMsgData.put("messClass", -1);
                subMsgData.put("content", subNameMap.get(k)+"实验室，化学品（"+v + "）已过期，请尽快确认处理！");

                Map<String,Object> subInfo = hxpUserecordMapper.selectSubInfoById(k);
                String safeUserId = "";
                if(subInfo != null){
                    // 通知实验室安全责任人
                    safeUserId = Optional.ofNullable(subInfo.get("safeUserId")).toString();
                    if(org.apache.commons.lang3.StringUtils.isNotBlank(safeUserId)){
                        String[] userIds = safeUserId.split(",");
                        Map<String, Object> msg;
                        List<Map<String, Object>> msgList = new ArrayList<>();
                        for (String userId : userIds) {
                            msg = new HashMap<>();
                            msg.put("joinUserId", userId);
                            msg.put("isRead", false);
                            msgList.add(msg);
                        }
                        subMsgData.put("messageUserList", msgList);

                        remoteMessageContentService.addDynamicMessage(subMsgData);
                    }
                }
            });
        }
    }

    public void wasExpire(List<HxpStockVO> list){
        //快过期处理
        List<Long> stockIds = new ArrayList<>();
        Map<Long, String> subMsg = new HashMap<>();
        List<Long> joinIds = new ArrayList<>();
        Map<Long, String> subNameMap = new HashMap<>();
        for (HxpStockVO hxpStock : list) {
            stockIds.add(hxpStock.getId());
            joinIds.add(hxpStock.getJoinId());

            subMsg.put(hxpStock.getSubId(), subMsg.get(hxpStock.getSubId()) == null ? "" : subMsg.get(hxpStock.getSubId())+"，" + hxpStock.getChemicalName());
            subNameMap.put(hxpStock.getSubId(),hxpStock.getSubName());
            // 报警记录
            HxpAlarmRecord hxpAlarmRecord = new HxpAlarmRecord();
            hxpAlarmRecord.setAlarmContent(hxpStock.getSubName()+"实验室，化学品（"+hxpStock.getChemicalName() + "）还有3天过期，请尽快确认处理。");
            hxpAlarmRecord.setAlarmType(1);
            hxpAlarmRecord.setHasValid(1);
            hxpAlarmRecord.setAlarmMode(1);
            hxpAlarmRecord.setAlarmTime(DateUtils.getNowDate());
            hxpAlarmRecord.setSubId(hxpStock.getSubId());
            hxpAlarmRecord.setHandlingStatus(1);
            hxpAlarmRecord.setStockId(hxpStock.getId());
            hxpAlarmRecord.setLiableUserIds(hxpStock.getSafeUserId());

            hxpAlarmRecordMapper.insertHxpAlarmRecord(hxpAlarmRecord);
        }
        if(stockIds.size() > 0){
            hxpStockMapper.updateExpiredByIds(stockIds);
        }
        if(joinIds.size() > 0){
            hxpChemicalJoinCabinetMapper.updateExpiredByIds(joinIds);
        }
        hxpChemicalJoinCabinetMapper.updateChemicalJoinCabinetByExpired();

        subMsg.forEach((k,v) -> {
            Map<String, Object> subMsgData = new HashMap<>();
            subMsgData.put("sendRange", 3);
            subMsgData.put("messClass", -1);
            subMsgData.put("content", subNameMap.get(k)+"实验室，化学品（"+v + "）快过期，请尽快确认处理！");

            Map<String,Object> subInfo = hxpUserecordMapper.selectSubInfoById(k);
            String safeUserId = "";
            if(subInfo != null){
                // 通知实验室安全责任人
                safeUserId = Optional.ofNullable(subInfo.get("safeUserId")).toString();
                if(org.apache.commons.lang3.StringUtils.isNotBlank(safeUserId)){
                    String[] userIds = safeUserId.split(",");
                    Map<String, Object> msg;
                    List<Map<String, Object>> msgList = new ArrayList<>();
                    for (String userId : userIds) {
                        msg = new HashMap<>();
                        msg.put("joinUserId", userId);
                        msg.put("isRead", false);
                        msgList.add(msg);
                    }
                    subMsgData.put("messageUserList", msgList);

                    remoteMessageContentService.addDynamicMessage(subMsgData);
                }
            }
        });
    }

    @Override
    public void outStock(HxpStock hxpStock) {
        //出库，将库存量置为 0
        // hxpStock.setOutUsages(BigDecimal.ZERO);
        hxpStock.setOutTime(DateUtils.getNowDate());
        hxpStock.setOutUserId(SecurityUtils.getUserId());

        HxpStock oldStock = selectHxpStockById(hxpStock.getId());
        if(oldStock == null){
            throw new ServiceException("操作失败：未找到数据，请刷新重试！");
        }

        HxpUserecord hxpUserecord = new HxpUserecord();
        hxpUserecord.setUseStatus(1);
        hxpUserecord.setStockId(hxpStock.getId());
        List<HxpUserecord> userecordList = hxpUserecordService.selectHxpUserecordList(hxpUserecord);
        if(userecordList.size() > 0){
            throw new ServiceException("化学品领用中，请在完成归还后再操作出库。");
        }

        HxpClassifyConfig hxpClassifyConfig = hxpClassifyConfigService.selectHxpClassifyConfigById(oldStock.getChemicalClassify());
        if(hxpClassifyConfig != null && hxpClassifyConfig.getOutStatus() == 2){
            if((hxpStock.getOutOneUser() == null || hxpStock.getOutTwoUser() == null)){
                throw new ServiceException("必须要双人验证成功才能出库！");
            }
        }

        if(hxpStock.getOutOneUser() == null){
            hxpStock.setOutOneUser(SecurityUtils.getUserId());
        }
        updateHxpStock(hxpStock);

        // 出库成功修改机柜化学品关联状态
        HxpChemicalJoinCabinet hxpCabinetJoinCabinet = new HxpChemicalJoinCabinet();
        hxpCabinetJoinCabinet.setId(oldStock.getJoinId());
        hxpCabinetJoinCabinet.setStatus(2);
        hxpCabinetJoinCabinetService.updateHxpChemicalJoinCabinet(hxpCabinetJoinCabinet);

        // 出库将 已过期，即将过期，超时未归还 报警信息自动处理
        hxpAlarmRecordMapper.updateByOutStock(hxpStock.getId());

        if(hxpStock.getLockLogId() != null){
            HxpCabinetlockLog hxpCabinetlockLog = new HxpCabinetlockLog();
            hxpCabinetlockLog.setId(hxpStock.getLockLogId());
            hxpCabinetlockLog.setStockId(hxpStock.getId());
            hxpCabinetlockLogMapper.updateHxpCabinetlockLog(hxpCabinetlockLog);
        }
    }
}
