package com.pcloud.book.personalstage.biz.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.constant.BookConstant;
import com.pcloud.book.book.dao.BookDao;
import com.pcloud.book.book.dto.BookDto;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.content.ResourceConsr;
import com.pcloud.book.consumer.erp.ErpConsr;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.custom.entity.CustomPlan;
import com.pcloud.book.custom.enums.PlanReadTypeEnum;
import com.pcloud.book.custom.mapper.CustomPlanMapper;
import com.pcloud.book.custom.mapper.CustomPlanModuleSuggestionMapper;
import com.pcloud.book.custom.vo.AddBookNameVO;
import com.pcloud.book.custom.vo.UserBookServiceVO;
import com.pcloud.book.group.dao.BookGroupDao;
import com.pcloud.book.group.enums.JoinGroupTypeEnum;
import com.pcloud.book.keywords.enums.ReplyTypeEnum;
import com.pcloud.book.mq.delay.DelayMessageSender;
import com.pcloud.book.pcloudkeyword.dao.PcloudRobotClassifyDao;
import com.pcloud.book.pcloudkeyword.dao.PcloudRobotDao;
import com.pcloud.book.pcloudkeyword.entity.PcloudRobot;
import com.pcloud.book.pcloudkeyword.entity.PcloudRobotClassify;
import com.pcloud.book.personalstage.biz.PersonalStageBiz;
import com.pcloud.book.personalstage.biz.PersonalStageJumpBiz;
import com.pcloud.book.personalstage.check.PersonalStageCheck;
import com.pcloud.book.personalstage.constant.PersonalStageConstant;
import com.pcloud.book.personalstage.dao.PersonalStageDao;
import com.pcloud.book.personalstage.dao.PersonalStageJumpDao;
import com.pcloud.book.personalstage.dao.PersonalStageJumpKeywordDao;
import com.pcloud.book.personalstage.dao.PersonalStageJumpLinkupDao;
import com.pcloud.book.personalstage.dao.PersonalStageProgressMessageDao;
import com.pcloud.book.personalstage.dao.PersonalStageReplyDao;
import com.pcloud.book.personalstage.dao.PersonalStageReplyItemDao;
import com.pcloud.book.personalstage.dao.PersonalStageUserDao;
import com.pcloud.book.personalstage.dao.PersonalStageWakeupDao;
import com.pcloud.book.personalstage.dao.ReplaceCodeDao;
import com.pcloud.book.personalstage.dao.UserReplaceCodeDao;
import com.pcloud.book.personalstage.dto.*;
import com.pcloud.book.personalstage.entity.PersonalStage;
import com.pcloud.book.personalstage.entity.PersonalStageProgressMessage;
import com.pcloud.book.personalstage.entity.PersonalStageReply;
import com.pcloud.book.personalstage.entity.PersonalStageReplyItem;
import com.pcloud.book.personalstage.entity.PersonalStageUser;
import com.pcloud.book.personalstage.entity.PersonalStageWakeup;
import com.pcloud.book.personalstage.entity.ReplaceCode;
import com.pcloud.book.personalstage.entity.UserReplaceCode;
import com.pcloud.book.personalstage.enums.JumpTypeEnum;
import com.pcloud.book.personalstage.enums.PersonalStageUserStateEnum;
import com.pcloud.book.personalstage.enums.SendModeEnum;
import com.pcloud.book.personalstage.enums.StageReplyRelevEnum;
import com.pcloud.book.personalstage.utils.CacheUtils;
import com.pcloud.book.personalstage.vo.request.AddScoreRequestVO;
import com.pcloud.book.personlstage.dto.UserReplaceCodeDTO;
import com.pcloud.book.push.dao.PersonalAppletsDao;
import com.pcloud.book.push.entity.PersonalApplets;
import com.pcloud.channelcenter.wechat.dto.BookServeParamVO;
import com.pcloud.channelcenter.wechat.vo.BookServeVO;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.core.mq.DelayQueueDTO;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.page.PageBean;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.BeanUtils;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.common.utils.httpclient.UrlUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.contentcenter.resource.dto.ResourceDTO;
import com.pcloud.erp.project.enums.ServiceLevelEnum;
import com.pcloud.wechatgroup.group.dto.GroupRobotDTO;
import com.pcloud.wechatgroup.group.dto.GroupUserDTO;
import com.sdk.wxgroup.RobotProcessTypeEnum;
import com.sdk.wxgroup.SendFileVO;
import com.sdk.wxgroup.SendMessageTypeEnum;
import com.sdk.wxgroup.SendPicMessageVO;
import com.sdk.wxgroup.SendTextMessageVO;
import com.sdk.wxgroup.WxGroupSDK;
import com.sdk.wxgroup.im.mimc.BusinessConstant;
import com.sdk.wxgroup.im.mimc.dto.SendMomentsDTO;
import com.sun.org.apache.xpath.internal.operations.Bool;

import org.apache.commons.collections.MapUtils;
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.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;

@Component("personalStageBiz")
public class PersonalStageBizImpl implements PersonalStageBiz {

    private static final Logger LOGGER = LoggerFactory.getLogger(PersonalStageBizImpl.class);

    @Autowired
    private PersonalStageDao personalStageDao;
    @Autowired
    private PersonalStageReplyDao personalStageReplyDao;
    @Autowired
    private PersonalStageReplyItemDao personalStageReplyItemDao;
    @Autowired
    private PersonalStageWakeupDao personalStageWakeupDao;
    @Autowired
    private PersonalStageCheck personalStageCheck;
    @Autowired
    private PersonalStageJumpDao personalStageJumpDao;
    @Autowired
    private PcloudRobotClassifyDao pcloudRobotClassifyDao;
    @Autowired
    private PcloudRobotDao pcloudRobotDao;
    @Autowired
    private PersonalStageUserDao personalStageUserDao;
    @Autowired
    private DelayMessageSender delayMessageSender;
    @Autowired
    private PersonalStageJumpKeywordDao personalStageJumpKeywordDao;
    @Autowired
    private PersonalStageJumpBiz personalStageJumpBiz;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private PersonalStageProgressMessageDao personalStageProgressMessageDao;
    @Autowired
    private PersonalStageJumpLinkupDao personalStageJumpLinkupDao;
    @Autowired
    private ResourceConsr resourceConsr;
    @Autowired
    private CustomPlanModuleSuggestionMapper customPlanModuleSuggestionMapper;
    @Autowired
    private UserReplaceCodeDao userReplaceCodeDao;
    @Autowired
    private ReplaceCodeDao replaceCodeDao;
    @Autowired
    private PersonalAppletsDao personalAppletsDao;
    @Autowired
    private CustomPlanMapper customPlanMapper;
    @Autowired
    private ErpConsr erpConsr;
    @Autowired
    private BookGroupDao bookGroupDao;
    @Autowired
    private BookDao bookDao;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;


    @Value("${wechat.group.link.prefix}")
    private String wechatLinkPrefix;

    private final static String PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE = "${PROGRESS_URL}";
    //需求单链接替换符
    private final static String PERSONAL_STAGE_PAPER_TEMPLATE = "${PROGRESS_URL&amp;ProgressId}";
    //需求单链接替换符
    private final static String PERSONAL_STAGE_PAPER_TEMPLATE1 = "${PROGRESS_URL&ProgressId}";

    // 项目进度路由
    private final static String PERSONAL_STAGE_PROJECT_PROGRESS = "/personalCenter/projectProgress";

    //需求定制单路由  https://wechat666.raysgo.com/personalCenter/questionNaire?paperId=679
    private final static String PERSONAL_STAGE_PAPER = "/personalCenter/questionNaire?paperId=";

    private final static String USER_SEND_CONTENT="${USER_SEND_CONTENT}";

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("新增阶段")
    @Override
    public Long createPersonalStage(PersonalStage personalStage) {
        personalStageCheck.createPersonalStageParamCheck(personalStage);
        Integer maxSeqNum = personalStageDao.getMaxSeqNum();
        personalStage.setSeqNum(maxSeqNum+1);
        personalStageDao.insert(personalStage);
        addWakeAndReply(personalStage);
        return personalStage.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("修改阶段")
    @Override
    public void updatePersonalStage(PersonalStage personalStage) {
        personalStageCheck.updatePersonalStageParamCheck(personalStage);
        personalStageDao.update(personalStage);
        deleteAddWakeAndReply(personalStage.getId());
        addWakeAndReply(personalStage);
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("删除阶段")
    @Override
    public void deletePersonalStage(Long id) {
        if (id==null){
            throw new BookBizException(BookBizException.PARAM_IS_NULL,"id不能为空！");
        }
        //校验是否是某个阶段的下一个阶段
        Integer count = personalStageJumpDao.getCountByPersonalStageId(id);
        if (count>0){
            throw new BookBizException(BookBizException.PARAM_IS_NULL,"该阶段为某个阶段的下一阶段，不能删除！");
        }
        personalStageDao.deleteById(id);
        deleteAddWakeAndReply(id);
    }

    @ParamLog("获取定制化阶段")
    @Override
    public PersonalStage getPersonalStage(Long id) {
        PersonalStage personalStage = personalStageDao.getById(id);
        if (personalStage==null){
            throw new BookBizException(BookBizException.ERROR,"没有该记录");
        }
        List<PersonalStageReply> replies = personalStageReplyDao.getListByPersonalStageId(id);
        Map<Long,List<PersonalStageReply>> wakeupReplyMap=new HashMap<>();
        if (!ListUtils.isEmpty(replies)){
            List<Long> replyIds=replies.stream().map(PersonalStageReply::getId).collect(Collectors.toList());
            List<PersonalStageReplyItem> replyItems = personalStageReplyItemDao.getListByReplyIds(replyIds);
            if (!ListUtils.isEmpty(replyItems)){
                fillReplyItems(replyItems);
                Map<Long,List<PersonalStageReplyItem>> itemMap=replyItems.stream().collect(Collectors.groupingBy(PersonalStageReplyItem::getPersonalStageReplyId));
                for (PersonalStageReply reply:replies){
                    reply.setPersonalStageReplyItems(itemMap.get(reply.getId()));
                }
            }
            personalStage.setStageNotKeywordReplies(replies.stream().filter(s->StageReplyRelevEnum.STAGE_NOT_KEYWORD.value.equals(s.getRelevanceType())).collect(Collectors.toList()));
            personalStage.setBookStageNotKeywordReplies(replies.stream().filter(s->StageReplyRelevEnum.BOOK_STAGE_NOT_KEYWORD.value.equals(s.getRelevanceType())).collect(Collectors.toList()));
            personalStage.setFusingNotKeywordReplies(replies.stream().filter(s->StageReplyRelevEnum.FUSING_NOT_KEYWORD.value.equals(s.getRelevanceType())).collect(Collectors.toList()));
            List<PersonalStageReply> wakeupReplies=replies.stream().filter(s->StageReplyRelevEnum.WAKEUP.value.equals(s.getRelevanceType())).collect(Collectors.toList());
            wakeupReplyMap=wakeupReplies.stream().collect(Collectors.groupingBy(PersonalStageReply::getRelevanceId));
        }
        List<PersonalStageWakeup> wakeups = personalStageWakeupDao.getListByPersonalStageId(id);
        for (PersonalStageWakeup wakeup:wakeups){
            wakeup.setWakeupReplies(wakeupReplyMap.get(wakeup.getId()));
        }
        personalStage.setPersonalStageWakeups(wakeups);
        return personalStage;
    }

    @ParamLog("填充回复项")
    private void fillReplyItems(List<PersonalStageReplyItem> replyItems) {
        if (ListUtils.isEmpty(replyItems)){
            return;
        }
        List<Long> resourceIds=replyItems.stream().filter(s->(ReplyTypeEnum.RESOURCE.value.equals(s.getReplyType())
                ||ReplyTypeEnum.AUDIO.value.equals(s.getReplyType()))&&s.getResourceId()!=null).map(PersonalStageReplyItem::getResourceId).collect(Collectors.toList());
        if (!ListUtils.isEmpty(resourceIds)){
            Map<Long, ResourceDTO> resourceDTOMap = resourceConsr.mapByIds(resourceIds);
            for (PersonalStageReplyItem item:replyItems) {
                Integer type = item.getReplyType();
                if (ReplyTypeEnum.RESOURCE.value.equals(type) || ReplyTypeEnum.AUDIO.value.equals(type)) {
                    ResourceDTO resourceDTO = resourceDTOMap.get(item.getResourceId());
                    if (resourceDTO != null) {
                        item.setResourceName(resourceDTO.getResourceName());
                        item.setResourceUrl(resourceDTO.getFileUrl());
                        item.setResourceTypeCode(resourceDTO.getTypeCode());
                        item.setResourceTypeName(resourceDTO.getTypeName());
                        item.setFileType(resourceDTO.getFileType());
                        item.setResourcePdfItems(resourceDTO.getResourcePdfItems());
                        item.setResourceOfficeItemDTOs(resourceDTO.getResourceOfficeItemDTOs());
                        item.setFileSize(resourceDTO.getFileSize());
                    }
                }
            }
        }
        for (PersonalStageReplyItem item:replyItems){
            Integer type=item.getReplyType();
            if (ReplyTypeEnum.PERSONALAPPLETS.value.equals(type)) {
                PersonalApplets byId = personalAppletsDao.getById(item.getPersonalAppletsId());
                item.setSlogan(byId.getSlogan());
                item.setSloganImgUrl(byId.getSloganImgUrl());
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("修改排序值")
    @Override
    public void updateSeqNum(PersonalStage personalStage) {
        if (personalStage==null||personalStage.getId()==null||personalStage.getSeqNum()==null){
            throw new BookBizException(BookBizException.PARAM_IS_NULL,"参数有误！");
        }
        personalStageDao.updateSeqNum(personalStage.getId(),personalStage.getSeqNum());
    }

    @ParamLog("删除唤醒和回复")
    private void deleteAddWakeAndReply(Long personalStageId) {
        List<Long> replyIds = personalStageReplyDao.getIdsByPersonalStageId(personalStageId);
        personalStageReplyDao.deleteByIds(replyIds);
        personalStageReplyItemDao.deleteByReplyIds(replyIds);
        personalStageWakeupDao.deleteByPersonalStageId(personalStageId);
    }

    @ParamLog("新增唤醒和回复")
    private void addWakeAndReply(PersonalStage personalStage) {
        Long personalStageId = personalStage.getId();
        List<PersonalStageReply> allReply=new ArrayList<>();
        if (!ListUtils.isEmpty(personalStage.getPersonalStageWakeups())){
            for (PersonalStageWakeup wakeup:personalStage.getPersonalStageWakeups()){
                wakeup.setPersonalStageId(personalStageId);
            }
            personalStageWakeupDao.batchInsert(personalStage.getPersonalStageWakeups());
            for (PersonalStageWakeup wakeup:personalStage.getPersonalStageWakeups()){
                Long wakeupId=wakeup.getId();
                for (PersonalStageReply reply:wakeup.getWakeupReplies()){
                    reply.setRelevanceType(StageReplyRelevEnum.WAKEUP.value);
                    reply.setRelevanceId(wakeupId);
                    reply.setPersonalStageId(personalStageId);
                }
                allReply.addAll(wakeup.getWakeupReplies());
            }
        }
        for (PersonalStageReply reply:personalStage.getStageNotKeywordReplies()){
            reply.setRelevanceType(StageReplyRelevEnum.STAGE_NOT_KEYWORD.value);
            reply.setPersonalStageId(personalStageId);
            reply.setRelevanceId(personalStageId);
        }
        allReply.addAll(personalStage.getStageNotKeywordReplies());
        if (!ListUtils.isEmpty(personalStage.getBookStageNotKeywordReplies())){
            for (PersonalStageReply reply:personalStage.getBookStageNotKeywordReplies()){
                reply.setRelevanceType(StageReplyRelevEnum.BOOK_STAGE_NOT_KEYWORD.value);
                reply.setPersonalStageId(personalStageId);
                reply.setRelevanceId(personalStageId);
            }
            allReply.addAll(personalStage.getBookStageNotKeywordReplies());
        }
        for (PersonalStageReply reply:personalStage.getFusingNotKeywordReplies()){
            reply.setRelevanceType(StageReplyRelevEnum.FUSING_NOT_KEYWORD.value);
            reply.setPersonalStageId(personalStageId);
            reply.setRelevanceId(personalStageId);
        }
        allReply.addAll(personalStage.getFusingNotKeywordReplies());
        personalStageReplyDao.batchInsert(allReply);
        List<PersonalStageReplyItem> allItems=new ArrayList<>();
        for (PersonalStageReply reply:allReply){
            Long replyId=reply.getId();
            for (PersonalStageReplyItem item:reply.getPersonalStageReplyItems()){
                item.setPersonalStageReplyId(replyId);
            }
            allItems.addAll(reply.getPersonalStageReplyItems());
        }
        personalStageReplyItemDao.batchInsert(allItems);
    }

    /**
     * 获取阶段列表
     */
    @Override
    public PageBean getPersonalStageList(Long robotClassifyId, PageParam pageParam) throws BizException {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("robotClassifyId", robotClassifyId);
        PageBean pageBean = personalStageDao.listPage(pageParam, paramMap, "getPersonalStageList");
        if (null == pageBean || ListUtils.isEmpty(pageBean.getRecordList())){
            return new PageBean();
        }
        //衔接语数量
        Map<Long, PersonalStageDTO> linkupCountMap = personalStageJumpLinkupDao.mapStageJumpLinkupCountByRobotClassify(robotClassifyId);
        for (Object object : pageBean.getRecordList()){
            PersonalStageDTO stageDTO = (PersonalStageDTO) object;
            if (!MapUtils.isEmpty(linkupCountMap) && linkupCountMap.containsKey(stageDTO.getId())){
                PersonalStageDTO linkup = linkupCountMap.get(stageDTO.getId());
                stageDTO.setJumpLinkupCount(linkup.getJumpLinkupCount());
            }
            //阶段跳转信息
            HashMap<String, Object> map = Maps.newHashMap();
            map.put("personalStageId", stageDTO.getId());
            PageBeanNew<PersonalStageJumpDto> pageBeanNew = personalStageJumpDao.listPageNew(new PageParam(0, 3), map, "getJumpList");
            if (null == pageBeanNew || ListUtils.isEmpty(pageBeanNew.getRecordList())){
                stageDTO.setPersonalStageJumpDtos(new ArrayList<>());
                stageDTO.setPersonalStageJumpCount(0);
            }else {
                stageDTO.setPersonalStageJumpDtos(pageBeanNew.getRecordList());
                stageDTO.setPersonalStageJumpCount(pageBeanNew.getTotalCount());
            }
        }
        return pageBean;
    }

    /**
     * 获取阶段列表
     */
    @Override
    public List<PersonalStageDTO> getPersonalStageListNoPage(Long robotClassifyId) throws BizException {
        return personalStageDao.getPersonalStageList(robotClassifyId);
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("发送关键词时处理用户定制化阶段")
    @Override
    public void userSendPersonalStage(String userWxId,String ip,Integer code,String robotId, String content) {
        Boolean hasRecord;
        PersonalStageUser last = personalStageUserDao.getLast(userWxId, robotId, null);
        PersonalStage personalStage;
        if (last!=null){
            hasRecord=true;
            personalStage=personalStageDao.getById(last.getPersonalStageId());
        }else {
            hasRecord=false;
            PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotId);
            Long robotClassifyId=pcloudRobot.getRobotType().longValue();
            personalStage = personalStageDao.getFirstStage(robotClassifyId);
        }
        //优先走获取书名阶段的0级书判断跳转逻辑
        if (dealBookNameStageZeroBook(userWxId, robotId, content,personalStage)){
            return;
        }
        Boolean iskeyword;
        if (StringUtil.isEmpty(content)){
            iskeyword=false;
        }else {
            //关键词库查询
            PersonalStageJumpKeywordDto dto=personalStageJumpKeywordDao.getByKeyword(personalStage.getId(),content, JumpTypeEnum.READER_TRIGGER.key);
            if (dto!=null){
                iskeyword=true;
            }else {
                iskeyword=false;
            }
        }
        //是关键词且有记录
        if (iskeyword){
            LOGGER.info("是关键词且有记录");
            String key = "PERSONAL_STAGE_JUMP_KEYWORD_LOCK".concat(userWxId).concat(robotId);
            try {
                // 加锁，一条一条数据进行处理
                while (!CacheUtils.lock(key)) {
                    Thread.sleep(100);
                }
                //调关键词处理逻辑
                personalStageJumpBiz.handlePersonalStageJump(userWxId,robotId,content,JumpTypeEnum.READER_TRIGGER,null,null);
            } catch (Exception e){
                LOGGER.info("缓存加锁失败，userWxId=" + userWxId +" robotId="+robotId);
            } finally {
                CacheUtils.unlock(key);
            }
        }
        //不是关键词且有记录
        if (!iskeyword&&hasRecord){
            //判断是否已经达到熔断标准
            if (personalStage!=null){
                Integer notKeywordSendCount =getSendNKeywordCountFromCache(personalStage.getId(),userWxId,robotId);
                if ((notKeywordSendCount!=null&&notKeywordSendCount>=personalStage.getNotKeywordFusingCount())
                      ||PersonalStageUserStateEnum.FUSING.value.equals(last.getState())){
                    // 走熔断
                    LOGGER.info("走熔断");
                    handleFusingReply(robotId,userWxId,ip,personalStage,last, personalStage.getPaperId());
                }else {
                    //走正常逻辑非关键词回复并且更新记录
                    if (PersonalStageUserStateEnum.NORMAL.value.equals(last.getState())
                        ||PersonalStageUserStateEnum.WAKEUP.value.equals(last.getState())){
                        LOGGER.info("走正常逻辑非关键词回复并且更新记录notKeywordSendCount:{}",notKeywordSendCount);
                        //如果是正常状态或者唤醒状态才回复，并且更新状态为正常状态
                        last.setNotKeywordSendCount(notKeywordSendCount+1);
                        last.setState(PersonalStageUserStateEnum.NORMAL.value);
                        personalStageUserDao.update(last);
                        sendNotKeywordReply(robotId,userWxId,ip,personalStage.getId(), last.getId(), content, personalStage.getSendMode(),notKeywordSendCount);
                    }
                }
            }
        }
        //不是关键词且没有记录
        if (!iskeyword&&!hasRecord){
            //走正常非关键词回复并且新增记录
            LOGGER.info("走正常非关键词回复并且新增记录");
            PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotId);
            Long robotClassifyId=pcloudRobot.getRobotType().longValue();
            PersonalStage firstStage = personalStageDao.getFirstStage(robotClassifyId);
            PersonalStageUser personalStageUser=new PersonalStageUser();
            personalStageUser.setRobotId(robotId);
            personalStageUser.setWxId(userWxId);
            personalStageUser.setState(PersonalStageUserStateEnum.NORMAL.value);
            personalStageUser.setNotKeywordSendCount(1);
            personalStageUser.setRobotClassifyId(robotClassifyId);
            personalStageUser.setPersonalStageId(firstStage.getId());
            personalStageUserDao.insert(personalStageUser);
            sendNotKeywordReply(robotId,userWxId,ip,personalStage.getId(), personalStageUser.getId(), content,firstStage.getSendMode(), 0);
        }
    }

    @ParamLog("获取书名阶段的0级书判断跳转逻辑")
    private Boolean dealBookNameStageZeroBook(String userWxId, String robotId, String content, PersonalStage personalStage) {
        if (personalStage.getReplaceCodeId()!=null){
            ReplaceCode replaceCode = replaceCodeDao.getById(personalStage.getReplaceCodeId());
            if (replaceCode!=null&&"${bookName}".equals(replaceCode.getReplaceCode())){
                Long personalStageId=personalStage.getId();
                String fileId=robotId+"_"+userWxId+"_"+personalStageId;
                String lastBookName = JedisClusterUtils.hget(PersonalStageConstant.LAST_NOT_KEYWORD_CONTENT_BEFORE_JUMP_STAGE_CACHE, fileId);
                if (StringUtil.isEmpty(lastBookName)){
                    return false;
                }
                Integer level = erpConsr.getBookServiceLevel(lastBookName);
                //判断0级书跳转且是跳转
                PersonalStageJumpKeywordDto zeroBookDto=personalStageJumpKeywordDao.getByKeyword(personalStageId,content, JumpTypeEnum.ZERO_BOOK.key);
                if (zeroBookDto!=null&&ServiceLevelEnum.ZERO_BOOK.value.equals(level)){
                    String bookGroupUrl=null;
                    Long bookGroupId=bookGroupDao.getIdByBookNameAndJoinGroupType(lastBookName, JoinGroupTypeEnum.GROUP_QRCODE.getCode());
                    if (bookGroupId!=null){
                        String link = wechatLinkPrefix +"/group/list?source_type=RAY&book_group_id="+bookGroupId;
                        bookGroupUrl = UrlUtils.getShortUrl4Own(link);
                    }
                    personalStageJumpBiz.handlePersonalStageJump(userWxId,robotId,content,JumpTypeEnum.ZERO_BOOK,bookGroupUrl,null);
                    return true;
                }
                //判断非0级书跳转且是跳转
                PersonalStageJumpKeywordDto noZeroBookDto=personalStageJumpKeywordDao.getByKeyword(personalStageId,content, JumpTypeEnum.NO_ZERO_BOOK.key);
                if (noZeroBookDto!=null&&ServiceLevelEnum.NOT_ZERO_BOOK.value.equals(level)){
                    personalStageJumpBiz.handlePersonalStageJump(userWxId,robotId,content,JumpTypeEnum.NO_ZERO_BOOK,null,null);
                    return true;
                }
                //判断无等级且已收录图书跳转
                PersonalStageJumpKeywordDto adviserBookDto=personalStageJumpKeywordDao.getByKeyword(personalStageId,content, JumpTypeEnum.ADVISER_BOOK.key);
                if (adviserBookDto!=null){
                    BookDto bookDto= bookDao.getAdviserBookByName(lastBookName);
                    if (bookDto!=null){
                        String adviserBookUrl=null;
                        //判断这个图书有没有资源
                        BookServeParamVO bookServeParamVO=new BookServeParamVO();
                        bookServeParamVO.setAdviserId(bookDto.getAdviserId());
                        bookServeParamVO.setBookId(bookDto.getBookId());
                        bookServeParamVO.setChannelId(bookDto.getChannelId());
                        List<BookServeVO> bookServeVOS = qrcodeSceneConsr.listBookServeIds(bookServeParamVO);
                        if (!ListUtils.isEmpty(bookServeVOS)){
                            String link = wechatLinkPrefix +"/dialog/resource?bookId="+bookDto.getBookId()+"&adviserId="+bookDto.getAdviserId()+"&channelId="+bookDto.getChannelId()+"&wxId=" + userWxId +"&robotWxId=" + robotId;
                            adviserBookUrl = UrlUtils.getShortUrl4Own(link);
                        }else {
                            adviserBookUrl = "没有资源";
                        }
                        personalStageJumpBiz.handlePersonalStageJump(userWxId,robotId,content,JumpTypeEnum.ADVISER_BOOK,null,adviserBookUrl);
                        return true;
                    }
                }
                PersonalStageJumpKeywordDto noAdviserBookDto=personalStageJumpKeywordDao.getByKeyword(personalStageId,content, JumpTypeEnum.NO_ADVISER_BOOK.key);
                if (noAdviserBookDto!=null){
                    //无等级未收录图书，但book中有
                    BookDto bookDto = bookDao.getBookByName(lastBookName);
                    if (null!=bookDto){
                        //目前跟无收录图书跳转一致，平台端未配置该跳转类型
                        personalStageJumpBiz.handleBookExistJump(userWxId,robotId,content,JumpTypeEnum.NO_ADVISER_BOOK, lastBookName);

                    }else {
                        personalStageJumpBiz.handlePersonalStageJump(userWxId,robotId,content,JumpTypeEnum.NO_ADVISER_BOOK,null,null);

                    }
                    return true;
                }
            }
        }
        return false;
    }


    @ParamLog("从缓存中获取发送非关键词次数")
    private synchronized Integer getSendNKeywordCountFromCache(Long personalStageId, String wxId, String robotId) {
        String key = PersonalStageConstant.NOT_SEND_KEYWORD_COUNT_LOCK + personalStageId;
        Integer count = 0;
        try {
            while (!CacheUtils.lock(key)) {
                Thread.sleep(100);
            }
            String cacheKey = PersonalStageConstant.USER_SEND_KEYWORD_COUNT_LOCK + personalStageId + "_" + wxId;
            long value = JedisClusterUtils.incr(cacheKey);
            if (value != 1) {
                return (int)value - 1;
            }
            count = personalStageUserDao.getNotKeywordSendCount(wxId, robotId, null);
            count = count == null ? 0 : count;
            JedisClusterUtils.set(cacheKey, (count.longValue() + 1) + "", 10 * 60);
            return count;
        } catch (Exception e) {
            LOGGER.warn("从缓存中获取发送非关键词次数失败，personalStageId=" + personalStageId +"wxId="+wxId+"robotId="+robotId);
        } finally {
            CacheUtils.unlock(key);
        }
        return count;
    }

    @Override
    @ParamLog("判断是否是定制化用户")
    public Boolean isPersonalStageUser(String robotId){
        //判断是否是平台端配置的小号
        try {
            PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotId);
            if (pcloudRobot!=null&&pcloudRobot.getRobotType()!=null){
                //查询该分类下的定制化阶段
                Long robotClassifyId=pcloudRobot.getRobotType().longValue();
                PcloudRobotClassify robotClassify = pcloudRobotClassifyDao.getById(robotClassifyId);
                if (robotClassify!=null){
                    //获取该分类下的阶段数量
                    Integer count=personalStageDao.getCountByRobotClassifyId(robotClassifyId);
                    if (count>0){
                        return true;
                    }
                }
            }
        }catch (Exception e) {
            LOGGER.error("判断是否是定制化用户失败" + e.getMessage(), e);
        }
        return false;
    }

    @ParamLog("加好友时插入初始状态")
    @Override
    public Long createAddUserStageUser(String robotId, String userWxId, String ip) {
        //查询第一个阶段
        PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotId);
        Long robotClassifyId=pcloudRobot.getRobotType().longValue();
        PersonalStage firstStage = personalStageDao.getFirstStage(robotClassifyId);
        if (firstStage==null){
            return null;
        }
        nextStageAddStageUserAndWakeupDelay (robotId, userWxId, ip, firstStage.getId());
        return firstStage.getId();
    }

    @ParamLog("处理延时唤醒")
    @Override
    public void dealDelayWakeup(DelayQueueDTO dto) {
        String wxId=dto.getKey();
        WakeupDelayDTO wakeupDelayDTO=(WakeupDelayDTO) dto.getMsg();
        //查询该用户最后的阶段
        PersonalStageUser last = personalStageUserDao.getLast(wxId, wakeupDelayDTO.getRobotId(), null);
        Long personalStageId = wakeupDelayDTO.getPersonalStageId();
        //判断用户是否在插入唤醒延时队列的当时阶段且是唤醒状态
        if (last==null||!PersonalStageUserStateEnum.WAKEUP.value.equals(last.getState())
                ||!last.getPersonalStageId().equals(personalStageId)){
            LOGGER.info("用户已跳阶段或者不是唤醒状态"+wakeupDelayDTO.toString());
            return;
        }
        PersonalStage personalStage=personalStageDao.getById(personalStageId);
        if (personalStage==null){
            LOGGER.info("未找到该阶段personalStageId="+personalStageId);
            return;
        }
        Long currentWakeupId=wakeupDelayDTO.getPersonalStageWakeupId();
        //发送唤醒内容
        List<Long> replyIds=personalStageReplyDao.getIdsByRelevance(StageReplyRelevEnum.WAKEUP.value,currentWakeupId);
        if (ListUtils.isEmpty(replyIds)){
            LOGGER.info("没有回复currentWakeupId="+currentWakeupId);
            return;
        }
        List<PersonalStageReplyItem> replyItems = personalStageReplyItemDao.getListByReplyIds(replyIds);
        if (ListUtils.isEmpty(replyItems)){
            LOGGER.info("没有回复项replyIds="+replyIds);
            return;
        }
        String robotId=wakeupDelayDTO.getRobotId();
        String userWxId=wakeupDelayDTO.getWxId();
        String ip=wakeupDelayDTO.getIp();
        this.replacePaperUrl(replyItems, robotId, userWxId, personalStage.getPaperId(),ip);
        //判断人工客服服务状态
        Boolean state = false;
        Integer serviceState = wechatGroupConsr.getServiceStateByRobotUser(robotId, userWxId);
        if (serviceState == 1){
            LOGGER.info("人工客服服务中，userWxId="+userWxId+"+robotId+"+robotId);
            state = true;
        }
        if (!state){//客服介入不发唤醒
            String uuId= UUID.randomUUID().toString();
            sendReplyItems(replyItems,robotId,userWxId,ip,wakeupDelayDTO.getPersonalStageUserId(),uuId,RobotProcessTypeEnum.PERSONAL_STAGE_WAKEUP);
        }
        //下一个延时
        List<PersonalStageWakeup> wakeups = personalStageWakeupDao.getListByPersonalStageId(personalStageId);
        int i=0;
        PersonalStageWakeup currentWakeup=null;
        for (PersonalStageWakeup wakeup:wakeups){
            i=i+1;
            if (currentWakeupId.equals(wakeup.getId())){
                currentWakeup=wakeup;
                break;
            }
        }
        if (currentWakeup!=null&&i>0&&i<wakeups.size()){
            PersonalStageWakeup nextWakeup=wakeups.get(i);
            Integer time=(nextWakeup.getToStageStartTime()-currentWakeup.getToStageStartTime())*1000;
            WakeupDelayDTO wakeupDelayDTONew=new WakeupDelayDTO();
            wakeupDelayDTONew.setPersonalStageWakeupId(nextWakeup.getId());
            wakeupDelayDTONew.setRobotId(robotId);
            wakeupDelayDTONew.setWxId(userWxId);
            wakeupDelayDTONew.setIp(ip);
            wakeupDelayDTONew.setPersonalStageId(personalStageId);
            wakeupDelayDTONew.setPersonalStageUserId(wakeupDelayDTO.getPersonalStageUserId());
            wakeupDelayDTO.setPersonalStageCreateTime(DateUtils.formatDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
            DelayQueueDTO delayQueueDTONew = DelayQueueDTO.builder().key(userWxId).type(PersonalStageConstant.PERSONALSTAGE_DELAY_WAKEUP).msg(wakeupDelayDTONew).timeout(time).build();
            delayMessageSender.send(delayQueueDTONew);
            LOGGER.info("下一个延时发送delayQueueDTONew="+delayQueueDTONew.toString());
        }


    }

    @ParamLog("下一阶段新增定制化阶段用户记录和唤醒延时")
    @Override
    public PersonalStageUser nextStageAddStageUserAndWakeupDelay(String robotId, String userWxId, String ip, Long personalStageId) {
        PersonalStageWakeup wakeup = personalStageWakeupDao.getFirstWakeup(personalStageId);
        PersonalStageUser personalStageUser=new PersonalStageUser();
        personalStageUser.setRobotId(robotId);
        personalStageUser.setWxId(userWxId);
        if (wakeup==null){
            //没有唤醒，设置状态为正常状态
            personalStageUser.setState(PersonalStageUserStateEnum.NORMAL.value);
        }else {
            //有唤醒，设置状态为唤醒状态
            personalStageUser.setState(PersonalStageUserStateEnum.WAKEUP.value);
        }
        personalStageUser.setNotKeywordSendCount(0);
        JedisClusterUtils.del(PersonalStageConstant.USER_SEND_KEYWORD_COUNT_LOCK + personalStageId + "_" + userWxId);
        //查询分类
        PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotId);
        Long robotClassifyId=pcloudRobot.getRobotType().longValue();
        personalStageUser.setRobotClassifyId(robotClassifyId);
        personalStageUser.setPersonalStageId(personalStageId);
        personalStageUserDao.insert(personalStageUser);

        // 设置定时跳转
        TimeJumpNextDTO timeJumpNextDTO = new TimeJumpNextDTO();
        timeJumpNextDTO.setRobotWxId(robotId);
        timeJumpNextDTO.setWxId(userWxId);
        timeJumpNextDTO.setPersonalStageId(personalStageId);
        timeJumpNextDTO.setPersonalStageUserId(personalStageUser.getId());
        timeJumpNextDTO.setIp(ip);
        personalStageJumpBiz.setDelayTimeJump(timeJumpNextDTO);

        //同时插入唤醒队列
        //查询第一个唤醒时长
        if (wakeup!=null){
            Integer toStageStartTime=wakeup.getToStageStartTime();
            WakeupDelayDTO wakeupDelayDTO=new WakeupDelayDTO();
            wakeupDelayDTO.setPersonalStageWakeupId(wakeup.getId());
            wakeupDelayDTO.setRobotId(robotId);
            wakeupDelayDTO.setWxId(userWxId);
            wakeupDelayDTO.setIp(ip);
            wakeupDelayDTO.setPersonalStageId(personalStageId);
            wakeupDelayDTO.setPersonalStageUserId(personalStageUser.getId());
            wakeupDelayDTO.setPersonalStageCreateTime(DateUtils.formatDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
            DelayQueueDTO delayQueueDTO = DelayQueueDTO.builder().key(userWxId).type(PersonalStageConstant.PERSONALSTAGE_DELAY_WAKEUP).msg(wakeupDelayDTO).timeout(toStageStartTime*1000).build();
            delayMessageSender.send(delayQueueDTO);
        }
        return personalStageUser;
    }

    @ParamLog("非关键词回复")
    @Override
    public void sendNotKeywordReply(String robotId, String userWxId, String ip, Long personalStageId, Long personalStageUserId,
                                    String userSendContent, Integer sendMode, Integer count) {
        if("重置体验".equals(userSendContent)){
            return;
        }
        if (!StringUtil.isEmpty(userSendContent)){
            String fileId=robotId+"_"+userWxId+"_"+personalStageId;
            JedisClusterUtils.hset(PersonalStageConstant.LAST_NOT_KEYWORD_CONTENT_BEFORE_JUMP_STAGE_CACHE, fileId,userSendContent);
        }
        //判断人工客服服务状态
        Integer serviceState = wechatGroupConsr.getServiceStateByRobotUser(robotId, userWxId);
        if (serviceState == 1){
            LOGGER.info("人工客服服务中，userWxId="+userWxId+"+robotId+"+robotId);
            return;
        }
        PersonalStage personalStage = personalStageDao.getById(personalStageId);
        List<PersonalStageReplyItem> items = new ArrayList<>();
        //确认是图书获取阶段 判断是否是特殊符号
        Boolean isSpecial = false;
        List<Long> ids = new ArrayList<>();
        if (null != personalStage && null != personalStage.getReplaceCodeId() && BookConstant.REPLACE_CODE_BOOK_NAME.equals(personalStage.getReplaceCodeId().intValue())
                && ((!StringUtil.isEmpty(userSendContent) && userSendContent.matches(BookConstant.SPECPATTEN)) || StringUtil.isEmpty(userSendContent))){
            ids = personalStageReplyDao.getIdsByRelevance(StageReplyRelevEnum.BOOK_STAGE_NOT_KEYWORD.value, personalStageId);
            if (!ListUtils.isEmpty(ids)){
                isSpecial = true;
            }
        }
        if (isSpecial){
            items = personalStageReplyItemDao.getListByReplyIds(ids);
        } else {
            PersonalStageReply personalStageReply = null;
            ids = personalStageReplyDao.getIdsByRelevance(StageReplyRelevEnum.STAGE_NOT_KEYWORD.value, personalStageId);
            Long replyId = null;
            if (ListUtils.isEmpty(ids)){
                return;
            }
            if (SendModeEnum.RADOM.value.equals(sendMode)){
                Random random = new Random();
                replyId=ids.get(random.nextInt(ids.size()));
                personalStageReply = personalStageReplyDao.getById(replyId);
            }else {
                if (null != count){
                    if ((count).intValue() >= ids.size()){
                        count = ids.size() -1;
                    }
                    LOGGER.info(StageReplyRelevEnum.STAGE_NOT_KEYWORD.value +":"+ personalStageId+":"+count);
                    personalStageReply = personalStageReplyDao.personalStageReply4Order(StageReplyRelevEnum.STAGE_NOT_KEYWORD.value, personalStageId,count);
                    replyId = personalStageReply.getId();
                }else {
                    throw new BookBizException(BookBizException.ERROR,"查询到用户发送的非关键词数量为0");
                }
                ids = Lists.newArrayList(replyId);
            }
           items = personalStageReplyItemDao.getListByReplyIds(Arrays.asList(replyId));
            if (ListUtils.isEmpty(items)){
                return;
            }
            //替换用户输入内容
            items=replaceUserSendContent(items,ids, userSendContent,robotId,userWxId,ip);
            if (ListUtils.isEmpty(items)){
                return;
            }
            //替换需求定制单链接
            this.replacePaperUrl(items, robotId, userWxId, personalStageReply.getPaperId(),ip);
        }
        String uuId= UUID.randomUUID().toString();
        sendReplyItems(items,robotId,userWxId,ip,personalStageUserId,uuId,RobotProcessTypeEnum.PERSONAL_STAGE_NOT_KEYWORD);
    }

    @ParamLog("替换用户输入内容")
    private List<PersonalStageReplyItem> replaceUserSendContent(List<PersonalStageReplyItem> items, List<Long> ids, String userSendContent, String robotId, String userWxId, String ip) {
        List<PersonalStageReplyItem> replyItems = personalStageReplyItemDao.getListByReplyIds(ids);
        Map<Long,List<PersonalStageReplyItem>> map=replyItems.stream().collect(Collectors.groupingBy(PersonalStageReplyItem::getPersonalStageReplyId));
        List<Long> idsNotHasSpe=new ArrayList<>();
        List<Long> idsHasSpe=new ArrayList<>();
        for (Long id:ids){
            List<PersonalStageReplyItem> ins=map.get(id);
            if (!ListUtils.isEmpty(ins)){
                Boolean normal=true;
                for (PersonalStageReplyItem replyItem:ins){
                    if (!StringUtil.isEmpty(replyItem.getContent())&&replyItem.getContent().contains(USER_SEND_CONTENT)){
                        normal=false;
                    }
                }
                if (normal){
                    idsNotHasSpe.add(id);
                }else {
                    idsHasSpe.add(id);
                }
            }
        }
        List<PersonalStageReplyItem> itemNew=new ArrayList<>();
        //如果用户没有输入文本
        if (StringUtil.isEmpty(userSendContent)){
            //找一个不带占位符的
            if (ListUtils.isEmpty(idsNotHasSpe)){
                SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
                sendTextMessageVO.setContent("哎哟 ～小主，你给我的不是书名啊。输入一本正在读或者感兴趣的书名，小睿就可以给你秀一下我的独家绝技哦");
                sendTextMessageVO.setAltId(robotId);
                sendTextMessageVO.setWxGroupId(userWxId);
                sendTextMessageVO.setIp(ip);
                sendTextMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                // TODO sdk.message
                wechatGroupConsr.sendMessage(JSON.toJSONString(sendTextMessageVO));
            }else {
                Random random = new Random();
                Long replyId=idsNotHasSpe.get(random.nextInt(idsNotHasSpe.size()));
                itemNew = personalStageReplyItemDao.getListByReplyIds(Arrays.asList(replyId));
            }
            return itemNew;
        }else {
            //用户输入文本优先给带特殊符号的
            if (!ListUtils.isEmpty(idsHasSpe)){
                Random random = new Random();
                Long replyId=idsHasSpe.get(random.nextInt(idsHasSpe.size()));
                itemNew = personalStageReplyItemDao.getListByReplyIds(Arrays.asList(replyId));
                for (PersonalStageReplyItem item:itemNew){
                    Integer type=item.getReplyType();
                    if (ReplyTypeEnum.TEXT.value.equals(type)&&item.getContent().contains(USER_SEND_CONTENT)) {
                        item.setContent(item.getContent().replace(USER_SEND_CONTENT,userSendContent));
                        //保持用户输入的内容
                        String key ="BOOK:USER_SEND_CONTENT:" + userWxId + "-" +robotId;
                        JedisClusterUtils.setJson(key, userSendContent);
                    }
                }
                return itemNew;
            }
        }
        return items;
    }

    @ParamLog("尝试插入单号")
    private void tryInsertNumber(Long personalStageUserId) {
        PersonalStageUser personalStageUser = personalStageUserDao.getById(personalStageUserId);
        if (StringUtil.isEmpty(personalStageUser.getRequireNumber())){
            String requireNumber = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss").concat(String.valueOf((int)((Math.random()*9+1)*100000)));
            personalStageUserDao.updateRequireNumber(personalStageUserId, requireNumber);
        }
       }

    @Override
    @ParamLog("替换进度链接")
    public String replaceProjectProgressUrl(String content, String robotId, String userWxId, Long personalStageUserId, String ip) {
        if(content.indexOf(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE_1) > -1){
            tryInsertNumber(personalStageUserId);
            String longUrl = wechatLinkPrefix.concat(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS).concat("?wxUserId=" + userWxId +
                    "&robotId=" + robotId + "&personalStageUserId=" + personalStageUserId + "&progressId=" + PersonalStageConstant.PERSONAL_STAGE_PROGRESS_1);
            content = content.replace(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE_1, UrlUtils.getShortUrl4Own(longUrl));
            //添加进度单回复延迟队列
            personalStageJumpBiz.addProgressDelay(userWxId, robotId, ip,PersonalStageConstant.PERSONAL_STAGE_PROGRESS_1);
        }else if (content.indexOf(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE_2) > -1){
            tryInsertNumber(personalStageUserId);
            String longUrl = wechatLinkPrefix.concat(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS).concat("?wxUserId=" + userWxId +
                    "&robotId=" + robotId + "&personalStageUserId=" + personalStageUserId + "&progressId=" + PersonalStageConstant.PERSONAL_STAGE_PROGRESS_2);
            content = content.replace(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE_2, UrlUtils.getShortUrl4Own(longUrl));
            //添加进度单回复延迟队列
            personalStageJumpBiz.addProgressDelay(userWxId, robotId, ip, PersonalStageConstant.PERSONAL_STAGE_PROGRESS_2);
        }else if (content.indexOf(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE_3) > -1){
            tryInsertNumber(personalStageUserId);
            String longUrl = wechatLinkPrefix.concat(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS).concat("?wxUserId=" + userWxId +
                    "&robotId=" + robotId + "&personalStageUserId=" + personalStageUserId + "&progressId=" +PersonalStageConstant.PERSONAL_STAGE_PROGRESS_3);
            content = content.replace(PersonalStageConstant.PERSONAL_STAGE_PROJECT_PROGRESS_TEMPLATE_3, UrlUtils.getShortUrl4Own(longUrl));
            //添加进度单回复延迟队列
            personalStageJumpBiz.addProgressDelay(userWxId, robotId, ip, PersonalStageConstant.PERSONAL_STAGE_PROGRESS_3);
        }
        if (content.indexOf(PersonalStageConstant.CUSTOM_PLAN) > -1) {
            String url = wechatLinkPrefix + "/personalCenter/madeProject?";
            Integer planId = customPlanModuleSuggestionMapper.getLatestPlanId(userWxId);
            //查询该用户最后的阶段
            PersonalStageUser last = personalStageUserDao.getLast(userWxId, robotId, null);
            if (null != planId) {
                String longUrl = url + "planId=" + planId + "&wxId=" + userWxId + "&robotWxId=" + robotId + (last != null && NumberUtil.isNumber(last.getPersonalStageId()) && last.getPersonalStageId() > 0 ? "&personalStageId=" + last.getPersonalStageId() : "");
                content = content.replace(PersonalStageConstant.CUSTOM_PLAN, UrlUtils.getShortUrl4Own(longUrl));
            }
        }
        content = replaceUserSendContent(content, robotId, userWxId);
        content = replaceReadingStyle(content, robotId, userWxId);
        content = replaceBookSearch(content, robotId, userWxId);
        content = replaceRights(content, robotId, userWxId);
        return content;
    }

    /**
     * 替换权益链接
     * @param content
     * @param robotId
     * @param userWxId
     * @return
     */
    private String replaceRights(String content, String robotId, String userWxId) {
        if(content.indexOf(PersonalStageConstant.PLAN_RIGHTS) > -1) {
            // 查询用户最近搜索的书
            UserReplaceCode userReplaceCodeBookName = userReplaceCodeDao.getLastOneUserReplace(userWxId, robotId, 1);
            if (userReplaceCodeBookName == null) {
                LOGGER.info("未找到用户输入的书名，无法进行跳转");
                return content.replace(PersonalStageConstant.PLAN_RIGHTS, "");
            }
            String bookName = userReplaceCodeBookName.getContent();
            if (StringUtil.isEmpty(bookName)) {
                LOGGER.info("图书名称为空，无法替换链接");
                return content.replace(PersonalStageConstant.PLAN_RIGHTS, "");
            }
            // 根据书名查询用户对应的权益（方案）
            List<Long> bookIds = erpConsr.getIdByBookName(bookName);
            if(ListUtils.isEmpty(bookIds)){
                LOGGER.info("在ERP中未找到对应的书，无法替换链接");
                return content.replace(PersonalStageConstant.PLAN_RIGHTS, "");
            }
            CustomPlan customPlan = customPlanMapper.getLastCustomPlanByBookIds(bookIds);
            if (customPlan == null) {
                LOGGER.info("未找到对应的权益，无法替换链接");
                return content.replace(PersonalStageConstant.PLAN_RIGHTS, "");
            }
            //查询该用户最后的阶段
            PersonalStageUser last = personalStageUserDao.getLast(userWxId, robotId, null);
            String h5link = wechatLinkPrefix + "/personalCenter/madeProject?planId=" + customPlan.getId() + "&wxId=" + userWxId + "&robotWxId=" + robotId +(last != null && NumberUtil.isNumber(last.getPersonalStageId()) && last.getPersonalStageId() > 0 ? "&personalStageId=" + last.getPersonalStageId() : "");
            return content.replace(PersonalStageConstant.PLAN_RIGHTS, UrlUtils.getShortUrl4Own(h5link));
        }
        return content;
    }

    @ParamLog("替换书籍搜索")
    private String replaceBookSearch(String content, String robotId, String userWxId) {
        if(content.indexOf(PersonalStageConstant.BOOK_SEARCH) > -1){
            //查询用户最近搜索的书
            UserBookServiceVO userBookServiceVO = customPlanModuleSuggestionMapper.getLastUserBookService(userWxId, robotId);
            if (userBookServiceVO!=null){
                Long userBookServiceId=userBookServiceVO.getId();
                String h5link = wechatLinkPrefix +"/dialog/search?wxId=" + userWxId +"&robotWxId=" + robotId + "&userBookServiceId=" +userBookServiceId;
                String linkUrl = UrlUtils.getShortUrl4Own(h5link);
                content = content.replace(PersonalStageConstant.BOOK_SEARCH, linkUrl);
            }
        }
        return content;
    }

    /**
     * 替换用户发送内容（书名）
     * @param content
     * @param robotId
     * @param userWxId
     * @return
     */
    public String replaceUserSendContent(String content, String robotId, String userWxId) {
        if(content.indexOf(USER_SEND_CONTENT) > -1){
            String key ="BOOK:USER_SEND_CONTENT:" + userWxId + "-" +robotId;
            String userSendContent = JedisClusterUtils.getJson(key, String.class);
            if (!StringUtil.isEmpty(userSendContent)){
                content = content.replace(USER_SEND_CONTENT, userSendContent);
            }
        }
        return content;
    }

    @ParamLog("替换阅读偏好")
    public String replaceReadingStyle(String linkupContent, String robotWxId, String userWxId){
        if (linkupContent.indexOf("${readingStyle=")>-1){
            Integer serchch = linkupContent.indexOf("${readingStyle=");
            String readingStyle= linkupContent.substring(serchch+15,serchch+19);
            String content = linkupContent.substring(serchch,serchch+20);
            if (!StringUtil.isEmpty(readingStyle) && !StringUtil.isEmpty(content)){
                //保持用户输入的内容
                String key ="BOOK:READING_STYLE:" + userWxId + "-" + robotWxId;
                JedisClusterUtils.setJson(key, readingStyle);
                //去掉衔接语这种替换符 ${readingStyle=xxxx}
                linkupContent = linkupContent.replace(content,readingStyle);
            }
        }
        return linkupContent;
    }

    @ParamLog("替换需求定制单链接")
    private void replacePaperUrl(List<PersonalStageReplyItem> items, String robotId, String userWxId, Long paperId, String ip){

        for (PersonalStageReplyItem item : items){
            if(ReplyTypeEnum.TEXT.value.equals(item.getReplyType())){
                if (item.getContent().indexOf(PERSONAL_STAGE_PAPER_TEMPLATE) > -1 ||
                        item.getContent().indexOf(PERSONAL_STAGE_PAPER_TEMPLATE1) > -1) {//包含链接
                    if (null == paperId) {
                        item.setContent(item.getContent().replace(PERSONAL_STAGE_PAPER_TEMPLATE, ""));
                        item.setContent(item.getContent().replace(PERSONAL_STAGE_PAPER_TEMPLATE1, ""));
                        return;
                    }
                    String longUrl = wechatLinkPrefix.concat(PERSONAL_STAGE_PAPER).concat(paperId.toString()).concat("&wxId=" + userWxId + "&robotWxId=" + robotId);
                    //由于前端给的替换符中的“&”可能会是“&amp;”,所以两种替换符都要换掉
                    String shortLink = UrlUtils.getShortUrl4Own(longUrl);
                    item.setContent(item.getContent().replace(PERSONAL_STAGE_PAPER_TEMPLATE, shortLink));
                    item.setContent(item.getContent().replace(PERSONAL_STAGE_PAPER_TEMPLATE1, shortLink));
                    //添加需求单延迟发送队列
                    personalStageJumpBiz.addPaperDelay(userWxId, robotId, ip, paperId);
                }
            }
        }
    }

    @ParamLog("非关键词熔断回复")
    @Override
    public void sendNotKeywordFusingReply(String robotId, String userWxId, String ip, Long personalStageId, Long personalStageUserId, Long paperId) {
        PersonalStage personalStage = personalStageDao.getById(personalStageId);
        PersonalStageUser personalStageUser = personalStageUserDao.getById(personalStageUserId);
        if(personalStage != null && personalStageUser != null) {
            Integer notReplyFusingCount = personalStage.getNotReplyFusingCount();
            if (notReplyFusingCount != null && personalStageUser.getFusingReplyCount() >= personalStage.getNotReplyFusingCount()) {
                return;
            }
        }
        //判断人工客服服务状态
        Integer serviceState = wechatGroupConsr.getServiceStateByRobotUser(robotId, userWxId);
        if (serviceState == 1){
            LOGGER.info("人工客服服务中，userWxId="+userWxId+"+robotId+"+robotId);
            return;
        }
        List<Long> ids = personalStageReplyDao.getIdsByRelevance(StageReplyRelevEnum.FUSING_NOT_KEYWORD.value, personalStageId);
        if (ListUtils.isEmpty(ids)) {
            return;
        }
        Random random = new Random();
        Long replyId = ids.get(random.nextInt(ids.size()));
        List<PersonalStageReplyItem> items = personalStageReplyItemDao.getListByReplyIds(Arrays.asList(replyId));
        if (ListUtils.isEmpty(items)){
            return;
        }
        this.replacePaperUrl(items, robotId, userWxId, paperId,ip);
        String uuId= UUID.randomUUID().toString();
        sendReplyItems(items,robotId,userWxId,ip,personalStageUserId,uuId,RobotProcessTypeEnum.PERSONAL_STAGE_FUSING);
        personalStageUserDao.updateFusingReplyCount(personalStageUserId);
    }

    @ParamLog("发送回复")
    private void sendReplyItems(List<PersonalStageReplyItem> replyItems,String robotId, String userWxId, String ip,Long personalStageUserId, String uuid, RobotProcessTypeEnum robotProcessType){
        for (PersonalStageReplyItem item:replyItems){
            Integer type=item.getReplyType();
            if (ReplyTypeEnum.TEXT.value.equals(type)) {
                SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
                sendTextMessageVO.setContent(replaceProjectProgressUrl(item.getContent(),robotId,userWxId,personalStageUserId,ip));
                sendTextMessageVO.setAltId(robotId);
                sendTextMessageVO.setWxGroupId(userWxId);
                sendTextMessageVO.setIp(ip);
                sendTextMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                sendTextMessageVO.setMessageGroupId(uuid);
                sendTextMessageVO.setRobotProcessType(robotProcessType);
                sendTextMessageVO.setIndex(replyItems.indexOf(item));
                sendTextMessageVO.setCounts(replyItems.size());
                wechatGroupConsr.sendMessage(JSON.toJSONString(sendTextMessageVO));;
            }
            if (ReplyTypeEnum.IMAGE.value.equals(type)) {
                SendPicMessageVO sendPicMessageVO = new SendPicMessageVO();
                sendPicMessageVO.setWxGroupId(userWxId);
                sendPicMessageVO.setAltId(robotId);
                sendPicMessageVO.setPicUrl(item.getPicUrl());
                sendPicMessageVO.setIp(ip);
                sendPicMessageVO.setCode(SendMessageTypeEnum.SELF.getCode());
                sendPicMessageVO.setMessageGroupId(uuid);
                sendPicMessageVO.setRobotProcessType(robotProcessType);
                sendPicMessageVO.setIndex(replyItems.indexOf(item));
                sendPicMessageVO.setCounts(replyItems.size());
                wechatGroupConsr.sendMessage(JSON.toJSONString(sendPicMessageVO));
            }
            if (ReplyTypeEnum.RESOURCE.value.equals(type)) {
                SendFileVO sendFileVO = new SendFileVO();
                Map<Long, ResourceDTO> map = resourceConsr.mapByIds(Arrays.asList(item.getResourceId()));
                ResourceDTO resourceDTO = map.get(item.getResourceId());
                if (resourceDTO != null) {
                    sendFileVO.setFileUrl(resourceDTO.getFileUrl());
                    String fileName = resourceDTO.getResourceName();
                    String fileType = resourceDTO.getFileType();
                    LOGGER.info("fileName="+fileName+"+fileType+"+fileType);
                    if (fileName.contains(fileType)){//去掉后缀
                        fileName = fileName.substring(0, fileName.indexOf(fileType)-1);
                    }
                    LOGGER.info("fileName="+fileName);
                    sendFileVO.setFileName(fileName);
                }
                sendFileVO.setIp(ip);
                sendFileVO.setAltId(robotId);
                sendFileVO.setWxId(userWxId);
                sendFileVO.setMessageGroupId(uuid);
                sendFileVO.setRobotProcessType(robotProcessType);
                sendFileVO.setIndex(replyItems.indexOf(item));
                sendFileVO.setCounts(replyItems.size());
                wechatGroupConsr.sendMessage(JSON.toJSONString(sendFileVO));
            }
            if (ReplyTypeEnum.AUDIO.value.equals(type)) {
                SendMomentsDTO sendMomentsDTO=new SendMomentsDTO();
                Map<Long, ResourceDTO> map = resourceConsr.mapByIds(Arrays.asList(item.getResourceId()));
                ResourceDTO resourceDTO = map.get(item.getResourceId());
                if (resourceDTO != null) {
                    GroupRobotDTO info = wechatGroupConsr.getGroupRobotByRobotId(robotId);
                    if (info!=null){
                        sendMomentsDTO.setIsMasterWx(info.getMasterWx());
                        sendMomentsDTO.setReceiveAccount(info.getMac());
                    }
                    sendMomentsDTO.setMomentType(BusinessConstant.MomentTypeEnum.SEND_WX_RECORD);
                    sendMomentsDTO.setContent(userWxId);
                    sendMomentsDTO.setLink(resourceDTO.getFileUrl());
                    sendMomentsDTO.setIp(ip);
                    sendMomentsDTO.setAltId(robotId);
                    sendMomentsDTO.setWxId(userWxId);
                    sendMomentsDTO.setMessageGroupId(uuid);
                    sendMomentsDTO.setRobotProcessType(robotProcessType);
                    sendMomentsDTO.setIndex(replyItems.indexOf(item));
                    sendMomentsDTO.setCounts(replyItems.size());
                    wechatGroupConsr.sendMessage(JSON.toJSONString(sendMomentsDTO));
                }
            }

            if (ReplyTypeEnum.PERSONALAPPLETS.value.equals(type)) {
                SendMomentsDTO sendMomentsDTO=new SendMomentsDTO();
                List<String> userWxIds=new ArrayList<>();
                userWxIds.add(userWxId);
                //发送的小程序
                PersonalApplets byId = personalAppletsDao.getById(item.getPersonalAppletsId());
                if(byId==null){
                    return;
                }
                GroupRobotDTO info = wechatGroupConsr.getGroupRobotByRobotId(robotId);
                if (info != null) {
                    sendMomentsDTO.setIsMasterWx(info.getMasterWx());
                    sendMomentsDTO.setReceiveAccount(info.getMac());
                }
                sendMomentsDTO.setMomentType(BusinessConstant.MomentTypeEnum.SEND_WX_MINI);
                sendMomentsDTO.setContent(byId.getAppletsId());//小程序id
                sendMomentsDTO.setLink(byId.getAppletsUrl());//小程序访问地址
                sendMomentsDTO.setImages(userWxIds);//发送人
                sendMomentsDTO.setLinkTitle(byId.getSlogan());//小程序宣传语
                sendMomentsDTO.setLinkDesc(byId.getSloganImgUrl());//小程序宣传图
                sendMomentsDTO.setIp(ip);
                sendMomentsDTO.setMessageGroupId(uuid);
                sendMomentsDTO.setCounts(replyItems.size());
                sendMomentsDTO.setIndex(replyItems.indexOf(item));
                sendMomentsDTO.setCode(SendMessageTypeEnum.SELF.getCode());
                sendMomentsDTO.setRobotProcessType(robotProcessType);
                sendMomentsDTO.setAltId(robotId);
                sendMomentsDTO.setWxId(userWxId);
                wechatGroupConsr.sendMessage(JSON.toJSONString(sendMomentsDTO));

            }
        }
    }

    @ParamLog("处理熔断回复情况")
    private void handleFusingReply(String robotId, String userWxId, String ip, PersonalStage personalStage, PersonalStageUser last, Long paperId) {
        if (!PersonalStageUserStateEnum.FUSING.value.equals(last.getState())) {
            // 置为熔断状态
            PersonalStageUser user = new PersonalStageUser();
            user.setId(last.getId());
            user.setState(PersonalStageUserStateEnum.FUSING.value);
            user.setNotKeywordSendCount(last.getNotKeywordSendCount()+1);
            personalStageUserDao.update(user);
            // 添加延迟队列
            FusingFinishDelayDTO delayDTO = new FusingFinishDelayDTO();
            delayDTO.setPersonalStageUserId(last.getId());
            delayDTO.setPersonalStageId(personalStage.getId());
            delayDTO.setRobotId(robotId);
            delayDTO.setWxId(userWxId);
            delayDTO.setIp(ip);
            DelayQueueDTO delayQueueDTO = DelayQueueDTO.builder().key(userWxId).type(PersonalStageConstant.PERSONALSTAGE_DELAY_FUSING)
                    .msg(delayDTO).timeout(personalStage.getNotKeywordFusingTime().intValue() * 1000).build();
            delayMessageSender.send(delayQueueDTO);
        }
        String key = "BOOK:PERSONAL_STAGE:FUSING:" + last.getId();
        if (!JedisClusterUtils.exists(key)) {
            // 发送熔断回复消息
            JedisClusterUtils.set(key, "true", 60);
            sendNotKeywordFusingReply(robotId, userWxId, ip, personalStage.getId(), last.getId(), paperId);
        }
    }

    @ParamLog("处理延时熔断结束")
    @Override
    public void dealDelayFusingFinish(DelayQueueDTO dto) {
        String wxId = dto.getKey();
        FusingFinishDelayDTO delayDTO = (FusingFinishDelayDTO) dto.getMsg();
        //查询该用户在该阶段的状态
        Long personalStageId = delayDTO.getPersonalStageId();
        Long personalStageUserId = delayDTO.getPersonalStageUserId();
        PersonalStageUser last = personalStageUserDao.getById(personalStageUserId);
        if (last == null || !PersonalStageUserStateEnum.FUSING.value.equals(last.getState())){
            return;
        }
        PersonalStage personalStage = personalStageDao.getById(personalStageId);
        if (personalStage == null){
            return;
        }
        // 将用户置为正常状态
        PersonalStageUser user = new PersonalStageUser();
        user.setId(personalStageUserId);
        user.setState(PersonalStageUserStateEnum.NORMAL.value);
        user.setNotKeywordSendCount(0);
        user.setFusingReplyCount(0);
        personalStageUserDao.update(user);
        //刪除发送非关键词次数緩存
        JedisClusterUtils.del(PersonalStageConstant.USER_SEND_KEYWORD_COUNT_LOCK + personalStageId + "_" + wxId);
    }

    @Override
    public PersonalStageProgressDTO getPersonalProgress(String wxUserId, Long personalStageUserId, Long progressId) {
        PersonalStageProgressDTO personalStageProgressDTO = new PersonalStageProgressDTO();
        PersonalStageUser personalStageUser = personalStageUserDao.getById(personalStageUserId);
        if(personalStageUser == null){
            return personalStageProgressDTO;
        }
        Date startTime = personalStageUser.getCreateTime();
        GroupUserDTO groupUserDTO = wechatGroupConsr.getWxUserInfoByWxUserId(wxUserId);
        personalStageProgressDTO.setWxUserId(wxUserId);
        personalStageProgressDTO.setHeadPic(groupUserDTO.getHeadPic());
        personalStageProgressDTO.setNickName(groupUserDTO.getNickName());
        personalStageProgressDTO.setSex(groupUserDTO.getSex());
        personalStageProgressDTO.setRequireNumber(personalStageUser.getRequireNumber());
        personalStageProgressDTO.setScore(personalStageUser.getScore());
        List<PersonalStageProgressMessage> personalStageProgressMessages =
                personalStageProgressMessageDao.getPersonalProgress(startTime,progressId);
        Integer totalProgress = personalStageProgressMessageDao.countProgressMessage(progressId);
        personalStageProgressDTO.setTotalProgress(totalProgress == null ? 0 : totalProgress);
        if (!ListUtils.isEmpty(personalStageProgressMessages)){
            List<PersonalStageProgressMessage> newList = this.setProgressTime(personalStageProgressMessages,startTime);
            personalStageProgressDTO.setPersonalStageProgressMessageList(newList);
        }
        return personalStageProgressDTO;
    }

    @Override
    public void updateScore(AddScoreRequestVO vo) {
        personalStageUserDao.updateScore(vo.getPersonalStageUserId(), vo.getScore());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean isFirstVisit(Long personalStageUserId) {
        PersonalStageUser personalStageUser = personalStageUserDao.getById(personalStageUserId);
        if (null == personalStageUser){
            return true;
        }
        if (personalStageUser.getProgressStartTime() == null){
            personalStageUser.setProgressStartTime(new Date());
            personalStageUserDao.update(personalStageUser);
            return true;
        }
        return false;
    }

    @ParamLog("当前用户阶段")
    @Override
    public PersonalStage getCurrentPersonalStage(String wxId, String robotId) {
        PersonalStageUser last = personalStageUserDao.getLast(wxId, robotId, null);
        if (last!=null){
            return personalStageDao.getById(last.getPersonalStageId());
        }
        return null;
    }

    @ParamLog("保存跳转关键词之前的一次非关键词")
    @Override
    public void addUserReplaceCodeBeforeJump(Long personalStageId,String wxId, String robotId) {
        String fileId=robotId+"_"+wxId+"_"+personalStageId;
        String content = JedisClusterUtils.hget(PersonalStageConstant.LAST_NOT_KEYWORD_CONTENT_BEFORE_JUMP_STAGE_CACHE, fileId);
        if (StringUtil.isEmpty(content)){
            return;
        }
        PersonalStage personalStage = personalStageDao.getById(personalStageId);
        if (personalStage==null||personalStage.getReplaceCodeId()==null){
            return;
        }
        UserReplaceCode userReplaceCode=new UserReplaceCode();
        userReplaceCode.setContent(content);
        userReplaceCode.setPersonalStageId(personalStageId);
        userReplaceCode.setWxId(wxId);
        userReplaceCode.setRobotId(robotId);
        userReplaceCode.setReplaceCodeId(personalStage.getReplaceCodeId());
        userReplaceCodeDao.insert(userReplaceCode);
        //清除缓存
        JedisClusterUtils.hdel(PersonalStageConstant.LAST_NOT_KEYWORD_CONTENT_BEFORE_JUMP_STAGE_CACHE,fileId);
    }

    @ParamLog("获取所有替换码")
    @Override
    public List<ReplaceCode> getAllReplaceCode() {
        return replaceCodeDao.getAll();
    }

    @Transactional(rollbackFor = Exception.class)
    @ParamLog("创建用户替换记录")
    @Override
    public void createUserReplaceCode(UserReplaceCodeDTO userReplaceCodeDTO) {
        UserReplaceCode userReplaceCode=new UserReplaceCode();
        BeanUtils.copyProperties(userReplaceCodeDTO,userReplaceCode);
        userReplaceCodeDao.insert(userReplaceCode);
    }

    @ParamLog("获取用户替换map")
    @Override
    public Map<String, String> getUserReplaceMap(String wxId, String robotId) {
        Map<String,String> map=new HashMap<>();
        if (StringUtil.isEmpty(wxId)||StringUtil.isEmpty(robotId)){
            return map;
        }
        List<UserReplaceCode> userReplaceCodes=userReplaceCodeDao.getLastUserReplace(wxId,robotId);
        List<ReplaceCode> all = replaceCodeDao.getAll();
        Map<Long,String> codeMap=new HashMap<>();
        for (ReplaceCode replaceCode:all){
            codeMap.put(replaceCode.getId(),replaceCode.getReplaceCode());
        }
        for (UserReplaceCode userReplaceCode:userReplaceCodes){
            String code=codeMap.get(userReplaceCode.getReplaceCodeId());
            if (!StringUtil.isEmpty(code)){
                map.put(code,userReplaceCode.getContent());
            }
        }
        return map;
    }

    private List<PersonalStageProgressMessage> setProgressTime(List<PersonalStageProgressMessage> personalStageProgressMessages, Date startTime) {
        List<PersonalStageProgressMessage> newList = new ArrayList<>();
        Date now = new Date();
        for (PersonalStageProgressMessage message : personalStageProgressMessages){
            message.setProgressTime(DateUtils.addMinute(startTime,message.getMinutes()));
            if (message.getProgressTime().after(now)){
                break;
            }
            message.setState(1);
            newList.add(message);
        }
        //将最后一个进度设置为进行中
        newList.get(newList.size()-1).setState(0);
        return newList;
    }

    @Override
    public ReplaceCodeDTO4CustomerService getUserReplaceMap4CustomerService(String wxId, String robotId) {
        ReplaceCodeDTO4CustomerService dto4CustomerService = new ReplaceCodeDTO4CustomerService();
        if (StringUtil.isEmpty(wxId)||StringUtil.isEmpty(robotId)){
            return dto4CustomerService;
        }
        List<ReplaceCode> all = replaceCodeDao.getAll();
        Long bookCodeId = null;
        Long serviceCodeId = null;
        for (ReplaceCode replaceCode:all){
            if ("${bookName}".equals(replaceCode.getReplaceCode())){
                bookCodeId = replaceCode.getId();
            } else if ("${serviceType}".equals(replaceCode.getReplaceCode())){
                serviceCodeId = replaceCode.getId();
            }
        }
        //书刊分类，目前取小号分类
        PcloudRobot pcloudRobot = pcloudRobotDao.getByWxId(robotId);
        if (null!= pcloudRobot && null !=pcloudRobot.getRobotType()){
           PcloudRobotClassify robotClassify = pcloudRobotClassifyDao.getById(pcloudRobot.getRobotType());
           String classifyName = robotClassify==null?"":robotClassify.getClassifyName();
           dto4CustomerService.setBookClassify(classifyName);
           dto4CustomerService.setBookClassifyList(Arrays.asList(classifyName));
        }
        //历史记录
        if (null!=bookCodeId){
            List<String> bookNameList = userReplaceCodeDao.getUserReplaceRecordByCodeId(wxId,robotId,bookCodeId);
            if (!ListUtils.isEmpty(bookNameList)){
                dto4CustomerService.setBookNameList(bookNameList);
                dto4CustomerService.setBookName(bookNameList.get(0));
            }
        }
        if (null!=serviceCodeId){
            List<String> serviceTypeList = userReplaceCodeDao.getUserReplaceRecordByCodeId(wxId,robotId,serviceCodeId);
            if (!ListUtils.isEmpty(serviceTypeList)){
                dto4CustomerService.setServiceTypeList(serviceTypeList);
                dto4CustomerService.setServiceType(serviceTypeList.get(0));
            }
        }
        return dto4CustomerService;
    }
}
