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

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import com.pcloud.appcenter.app.dto.AppDto;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.biz.BookKeywordWarehouseBiz;
import com.pcloud.book.consumer.app.AppConsr;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.content.ResourceConsr;
import com.pcloud.book.consumer.live.LiveCons;
import com.pcloud.book.consumer.resource.ProductConsr;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.group.biz.BookGroupAppBiz;
import com.pcloud.book.group.biz.BookGroupBiz;
import com.pcloud.book.group.biz.BookGroupClassifyBiz;
import com.pcloud.book.group.biz.GroupQrcodeBiz;
import com.pcloud.book.group.biz.WeixinQrcodeBiz;
import com.pcloud.book.group.dao.AppTouchRecordDao;
import com.pcloud.book.group.dao.BookGroupCipherUserDao;
import com.pcloud.book.group.dao.BookGroupClassifyDao;
import com.pcloud.book.group.dao.BookGroupDao;
import com.pcloud.book.group.dao.GroupQrcodeDao;
import com.pcloud.book.group.dao.JoinGroupCipherDao;
import com.pcloud.book.group.dao.WxUserWechatRelevanceDao;
import com.pcloud.book.group.dto.BookGroupDTO;
import com.pcloud.book.group.dto.BookWxQrcodeDTO;
import com.pcloud.book.group.dto.GroupClassifyQrcodeDTO;
import com.pcloud.book.group.entity.AppTouchRecord;
import com.pcloud.book.group.entity.BookGroup;
import com.pcloud.book.group.entity.BookGroupCipherUser;
import com.pcloud.book.group.entity.BookGroupClassify;
import com.pcloud.book.group.entity.BookGroupServe;
import com.pcloud.book.group.entity.GroupQrcode;
import com.pcloud.book.group.enums.AppAndProductTypeEnum;
import com.pcloud.book.group.enums.JoinGroupTypeEnum;
import com.pcloud.book.group.enums.QrcodeStatusEnum;
import com.pcloud.book.group.enums.TouchTypeEnum;
import com.pcloud.book.group.enums.UpdateStatusEnum;
import com.pcloud.book.group.tools.SendSelfMsgTools;
import com.pcloud.book.group.tools.SendWeixinRequestTools;
import com.pcloud.book.group.vo.ClassifyNameVO;
import com.pcloud.book.group.vo.ClassifyVO;
import com.pcloud.book.group.vo.GroupQrcode4ClassifyVO;
import com.pcloud.book.group.vo.ListClassifyVO;
import com.pcloud.book.keywords.biz.BookKeywordBiz;
import com.pcloud.book.keywords.dao.BookKeywordDao;
import com.pcloud.book.keywords.dao.BookKeywordRecordDao;
import com.pcloud.book.keywords.dao.KeywordDao;
import com.pcloud.book.keywords.dao.SelfRobotKeywordDao;
import com.pcloud.book.keywords.dto.KeywordDTO;
import com.pcloud.book.keywords.dto.KeywordStatisticsDTO;
import com.pcloud.book.keywords.dto.ReplyKeywordDTO;
import com.pcloud.book.keywords.dto.ServiceResourceDTO;
import com.pcloud.book.keywords.entity.BookKeyword;
import com.pcloud.book.keywords.entity.BookKeywordRecord;
import com.pcloud.book.keywords.entity.Keyword;
import com.pcloud.book.keywords.entity.SelfRobotKeyword;
import com.pcloud.book.keywords.enums.ReplyTypeEnum;
import com.pcloud.book.keywords.vo.DeleteKeywordVO;
import com.pcloud.book.keywords.vo.KeywordVO;
import com.pcloud.book.keywords.vo.ListKeywordParam;
import com.pcloud.book.keywords.vo.ListKeywordVO;
import com.pcloud.book.keywords.vo.QrWeixinParam;
import com.pcloud.book.keywords.vo.SetKeywordVO;
import com.pcloud.book.keywords.vo.SetRankVO;
import com.pcloud.book.keywords.vo.UpdateKeywordVO;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.channelcenter.base.constants.ChannelEnum;
import com.pcloud.channelcenter.qrcode.service.QrcodeSceneService;
import com.pcloud.channelcenter.qrcode.vo.MessageBookVO;
import com.pcloud.channelcenter.qrcode.vo.QrWeixinParamVO;
import com.pcloud.channelcenter.wechat.dto.AccountSettingDto;
import com.pcloud.common.constant.CacheConstant;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.ResponseHandleUtil;
import com.pcloud.common.utils.bean.ResponesUtils;
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.liveapp.live.dto.CourseListDto;
import com.pcloud.resourcecenter.product.dto.ProductDto;
import com.pcloud.resourcecenter.product.dto.ProductTypeDto;
import com.pcloud.wechatgroup.group.dto.RobotReplyDTO;
import com.pcloud.wechatgroup.message.dto.SendTextDTO;
import com.sdk.wxgroup.ChangeNameVO;
import com.sdk.wxgroup.SendArticleMessageVO;
import com.sdk.wxgroup.SendFileVO;
import com.sdk.wxgroup.SendGroupInviteVO;
import com.sdk.wxgroup.SendMessageTypeEnum;
import com.sdk.wxgroup.SendPicMessageVO;
import com.sdk.wxgroup.SendTextMessageVO;
import com.sdk.wxgroup.WxGroupSDK;

import org.apache.commons.collections.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeSet;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lily
 * @date 2019/4/25 10:47
 */
@Slf4j
@Component("bookKeywordBiz")
public class BookKeywordBizImpl implements BookKeywordBiz {
    @Autowired
    private KeywordDao keywordDao;
    @Autowired
    private BookGroupDao bookGroupDao;
    @Autowired
    private BookKeywordDao bookKeywordDao;
    @Autowired
    private BookGroupClassifyBiz bookGroupClassifyBiz;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private BookKeywordRecordDao bookKeywordRecordDao;
    @Autowired
    private ProductConsr productConsr;
    @Autowired
    private AppConsr appConsr;
    @Autowired
    private AppTouchRecordDao appTouchRecordDao;
    @Autowired
    private GroupQrcodeDao groupQrcodeDao;
    @Resource
    private BookKeywordWarehouseBiz bookKeywordWarehouseBiz;
    @Autowired
    private BookGroupClassifyDao bookGroupClassifyDao;
    @Autowired
    private QrcodeSceneService qrcodeSceneService;
    @Autowired
    private BookGroupBiz bookGroupBiz;
    @Autowired
    private GroupQrcodeBiz groupQrcodeBiz;
    @Autowired
    private JoinGroupCipherDao joinGroupCipherDao;
    @Autowired
    private LiveCons liveCons;
    @Autowired
    private BookGroupCipherUserDao bookGroupCipherUserDao;
    @Autowired
    private WeixinQrcodeBiz weixinQrcodeBiz;
    @Autowired
    private BookGroupAppBiz bookGroupAppBiz;
    @Autowired
    private WxUserWechatRelevanceDao wxUserWechatRelevanceDao;
    @Autowired
    private SelfRobotKeywordDao selfRobotKeywordDao;
    @Autowired
    private ResourceConsr resourceConsr;
    /**
     * 字符串切割长度
     */
    private static final Integer LE = 1000;

    private static final String REPLY_GUIDE_CACHE = "BOOK:replyGuideCache";

    private static final String REPLY_ERROR_SHORT_BOOK_NAME_CACHE = "BOOK:replyErrorShortBookNameCache";

    @Override
    @ParamLog("新增关键词")
    @Transactional(rollbackFor = Exception.class)
    public void insertKeyword(SetKeywordVO setKeywordVO) {
        if (null == setKeywordVO || setKeywordVO.check()) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "应用/作品信息为空");
        }
        if (setKeywordVO.getContent() != null && setKeywordVO.getContent().length() > 1000) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "回复内容超出限制！");
        }
        if (setKeywordVO.getClassifyId() == null) {
            setKeywordVO.setClassifyId(0L);
        }
        //获取图书相关信息
        BookGroupDTO bookGroupDTO = bookGroupDao.getDTOById(setKeywordVO.getBookGroupId());
        if (bookGroupDTO == null) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "该社群码不存在！");
        }
        //校验关键词
        checkKeyword(setKeywordVO.getKeywords(), setKeywordVO.getClassifyId(), setKeywordVO.getBookGroupId(), null);
        Integer count = bookKeywordDao.getKeywordCount(setKeywordVO.getBookGroupId(), setKeywordVO.getClassifyId());
        if (count >= 200) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "超出关键词数量限制");
        }
        //新增关键词
        Keyword keyword = new Keyword();
        BeanUtils.copyProperties(setKeywordVO, keyword);
        keyword.setCreateUser(setKeywordVO.getUserId());
        keywordDao.insert(keyword);
        //上架商品
        List<Long> productIds = new ArrayList<>();
        if (ReplyTypeEnum.APP.value.equals(keyword.getReplyType()) && "PRODUCT".equalsIgnoreCase(keyword.getServeType())) {
            productIds.add(keyword.getServeId());
        }
        productConsr.productAutoOnShelves(bookGroupDTO.getChannelId(), productIds);
        //新增关键词与分类或者图书的关系
        //按群创建
        if (setKeywordVO.getSetType() == 1) {
            BookKeyword bookKeyword = new BookKeyword();
            BeanUtils.copyProperties(setKeywordVO, bookKeyword);
            bookKeyword.setKeywordId(keyword.getId());
            bookKeyword.setBookId(bookGroupDTO.getBookId());
            bookKeyword.setChannelId(bookGroupDTO.getChannelId());
            //获取最大排序值
            Integer rank = bookKeywordDao.getMaxRank(setKeywordVO.getBookGroupId(), bookKeyword.getClassifyId());
            bookKeyword.setRank(rank + 1);
            bookKeyword.setCreateUser(setKeywordVO.getUserId());
            if (null != setKeywordVO.getAddWarehouse() && 1 == setKeywordVO.getAddWarehouse()) {
                setKeywordVO.setChannelId(bookGroupDTO.getChannelId());
                final Long warehouseId = bookKeywordWarehouseBiz.addBookKeyword(setKeywordVO);
                bookKeyword.setWarehouseId(warehouseId);
                bookKeyword.setIsWarehouse(1);
            }
            if (null == bookKeyword.getIsWarehouse()) {
                bookKeyword.setIsWarehouse(0);
            }
            if (null == bookKeyword.getWarehouseId()) {
                bookKeyword.setWarehouseId(0L);
            }
            bookKeyword.setIsEdit(1);
            bookKeywordDao.insert(bookKeyword);
            bookKeyword.setKeyword(keyword);
            bookGroupAppBiz.addAppKeywordToBookGroupApp(Arrays.asList(bookKeyword));
        } else {
            //按书创建
            List<ClassifyNameVO> classifyNameVOS = bookGroupClassifyDao.listClassifyByRank(setKeywordVO.getBookGroupId());
            List<BookKeyword> bookKeywords = new ArrayList<>();
            //创建书的记录
            BookKeyword bookKeyword = new BookKeyword();
            BeanUtils.copyProperties(setKeywordVO, bookKeyword);
            bookKeyword.setKeywordId(keyword.getId());
            bookKeyword.setBookId(bookGroupDTO.getBookId());
            bookKeyword.setChannelId(bookGroupDTO.getChannelId());
            //获取最大排序值
            Integer rank = bookKeywordDao.getMaxRank(setKeywordVO.getBookGroupId(), bookKeyword.getClassifyId());
            bookKeyword.setRank(rank + 1);
            bookKeyword.setCreateUser(setKeywordVO.getUserId());
            if (null != setKeywordVO.getAddWarehouse() && 1 == setKeywordVO.getAddWarehouse()) {
                setKeywordVO.setChannelId(bookGroupDTO.getChannelId());
                final Long warehouseId = bookKeywordWarehouseBiz.addBookKeyword(setKeywordVO);
                bookKeyword.setWarehouseId(warehouseId);
                bookKeyword.setIsWarehouse(1);
            }
            //创建群的记录
            if (!ListUtils.isEmpty(classifyNameVOS)) {
                classifyNameVOS.forEach(e -> {
                    BookKeyword cKeyword = new BookKeyword();
                    BeanUtils.copyProperties(setKeywordVO, cKeyword);
                    cKeyword.setKeywordId(keyword.getId());
                    cKeyword.setBookId(bookGroupDTO.getBookId());
                    cKeyword.setChannelId(bookGroupDTO.getChannelId());
                    cKeyword.setClassifyId(e.getId());
                    //获取最大排序值
                    Integer rank1 = bookKeywordDao.getMaxRank(setKeywordVO.getBookGroupId(), cKeyword.getClassifyId());
                    cKeyword.setRank(rank1 + 1);
                    cKeyword.setCreateUser(setKeywordVO.getUserId());
                    if (null != setKeywordVO.getAddWarehouse() && 1 == setKeywordVO.getAddWarehouse()) {
                        // 书入库一遍，同样的就不要入库了
//                        setKeywordVO.setChannelId(bookGroupDTO.getChannelId());
//                        final Long warehouseId = bookKeywordWarehouseBiz.addBookKeyword(setKeywordVO);
                        cKeyword.setWarehouseId(bookKeyword.getWarehouseId());
                        cKeyword.setIsWarehouse(1);
                    }
                    if (null == cKeyword.getIsWarehouse()) {
                        cKeyword.setIsWarehouse(0);
                    }
                    if (null == cKeyword.getWarehouseId()) {
                        cKeyword.setWarehouseId(0L);
                    }
                    if (0 == cKeyword.getClassifyId()) {
                        cKeyword.setIsEdit(1);
                    } else {
                        cKeyword.setIsEdit(0);
                    }
                    cKeyword.setKeyword(keyword);
                    bookKeywords.add(cKeyword);
                });
            }
            if (null == bookKeyword.getIsWarehouse()) {
                bookKeyword.setIsWarehouse(0);
            }
            if (null == bookKeyword.getWarehouseId()) {
                bookKeyword.setWarehouseId(0L);
            }
            if (0 == bookKeyword.getClassifyId()) {
                bookKeyword.setIsEdit(1);
            } else {
                bookKeyword.setIsEdit(0);
            }
            bookKeyword.setKeyword(keyword);
            bookKeywords.add(bookKeyword);
            bookKeywordDao.insert(bookKeywords);
            bookGroupAppBiz.addAppKeywordToBookGroupApp(bookKeywords);
        }

    }

    @Override
    @ParamLog("批量新增关键词")
    @Transactional(rollbackFor = {Exception.class})
    public void insertKeywords(List<SetKeywordVO> setKeywordVOs, Long partyId) {
        if (CollectionUtils.isEmpty(setKeywordVOs) || null == partyId) {
            log.info("[insertKeywords] : setKeywordVOs:{}, partyId:{}", setKeywordVOs, partyId);
            return;
        }
        for (SetKeywordVO vo : setKeywordVOs) {
            vo.setUserId(partyId);
            this.insertKeyword(vo);
        }
    }

    @ParamLog("校验关键词是否重复")
    private void checkKeyword(String keywords, Long classifyId, Long bookGroupId, Long keywordId) {
        Boolean isHaveKeyword = bookKeywordDao.checkKeyword(keywords, classifyId, bookGroupId, keywordId);
        if (isHaveKeyword) {
            throw new BookBizException(BookBizException.ERROR, "关键词" + keywords + "已存在！");
        }
    }

    @Override
    @ParamLog("更新关键词")
    @Transactional(rollbackFor = Exception.class)
    public void updateKeyword(UpdateKeywordVO updateKeywordVO, Long partyId) {
        checkKeyword(updateKeywordVO.getKeywords(), updateKeywordVO.getClassifyId(), updateKeywordVO.getBookGroupId(), updateKeywordVO.getKeywordId());
        //获取图书相关信息
        BookGroupDTO bookGroupDTO = bookGroupDao.getDTOById(updateKeywordVO.getBookGroupId());
        if (bookGroupDTO == null) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "该社群码不存在！");
        }
        if (null != updateKeywordVO.getAddWarehouse() && 1 == updateKeywordVO.getAddWarehouse()) {
            SetKeywordVO v = new SetKeywordVO();
            BeanUtils.copyProperties(updateKeywordVO, v);
            if (ChannelEnum.APP.value.equals(updateKeywordVO.getServeType())) {
                final AppDto baseById = appConsr.getBaseById(updateKeywordVO.getServeId());
                if (null == baseById) {
                    throw new BookBizException(BookBizException.ID_NOT_EXIST, "应用不存在");
                }
                v.setTypeCode(baseById.getTypeCode());
            }
            if (ChannelEnum.PRODUCT.value.equals(updateKeywordVO.getServeType())) {
                final ProductDto proBaseById = productConsr.getProBaseById(updateKeywordVO.getServeId());
                if (null == proBaseById) {
                    throw new BookBizException(BookBizException.ID_NOT_EXIST, "作品不存在");
                }
                v.setTypeCode(proBaseById.getProductTypeCode());
            }
            v.setUserId(partyId);
            v.setChannelId(bookGroupDTO.getChannelId());
            final Long warehouseId = this.bookKeywordWarehouseBiz.addBookKeyword(v);
            this.bookKeywordDao.updateIsWarehouse(updateKeywordVO.getBookKeywordId(), warehouseId);
        }
        Keyword keyword = new Keyword();
        BeanUtils.copyProperties(updateKeywordVO, keyword);
        keyword.setId(updateKeywordVO.getKeywordId());
        keyword.setUpdateUser(partyId);
        keywordDao.update(keyword);
        //上架商品
        List<Long> productIds = new ArrayList<>();
        if (ReplyTypeEnum.APP.value.equals(keyword.getReplyType()) && ChannelEnum.PRODUCT.value.equalsIgnoreCase(keyword.getServeType())) {
            productIds.add(keyword.getServeId());
        }
        productConsr.productAutoOnShelves(bookGroupDTO.getChannelId(), productIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ParamLog("删除关键词")
    public void deleteKeyword(DeleteKeywordVO deleteKeywordVO, Long partyId) {
        if (deleteKeywordVO == null || deleteKeywordVO.getIsEdit() == null || deleteKeywordVO.getKeywordId() == null) {
            throw new BookBizException(BookBizException.ERROR, "缺少必要参数");
        }
        if (deleteKeywordVO.getClassifyId() == null) {
            deleteKeywordVO.setClassifyId(0L);
        }
        if (deleteKeywordVO.getIsEdit() == 1) {
            keywordDao.deleteById(deleteKeywordVO.getKeywordId(), partyId);
            bookKeywordDao.deleteById(deleteKeywordVO.getKeywordId(), partyId);
        } else {
            bookKeywordDao.deleteKeywords(deleteKeywordVO.getKeywordId(), deleteKeywordVO.getBookGroupId(), deleteKeywordVO.getClassifyId(), partyId);
        }

    }

    @Override
    @ParamLog("设置排序值")
    public void setRank(SetRankVO setRankVO, Long partyId) {
        BookKeyword bookKeyword = new BookKeyword();
        bookKeyword.setId(setRankVO.getBookKeywordId());
        bookKeyword.setRank(setRankVO.getRank());
        bookKeyword.setUpdateUser(partyId);
        KeywordVO byBookKeyword = bookKeywordDao.getByBookKeyword(setRankVO.getBookKeywordId());
        if (byBookKeyword != null && (byBookKeyword.getClassifyId() == null || byBookKeyword.getClassifyId() == 0)) {
            Long bookGroupId = byBookKeyword.getBookGroupId();
            Long keywordId = byBookKeyword.getKeywordId();
            bookKeywordDao.updateRank(bookGroupId, setRankVO.getRank(), partyId, keywordId);
        } else {
            bookKeywordDao.setRank(bookKeyword);
        }
    }

    @Override
    @ParamLog(value = "获取关键词列表", isAfterReturn = false)
    public PageBeanNew<ListKeywordVO> listKeywordsByClassify(ListKeywordParam listKeywordParam) {
        PageParam pageParam = new PageParam(listKeywordParam.getCurrentPage(), listKeywordParam.getNumPerPage());
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("keywords", listKeywordParam.getKeywords());
        paramMap.put("classifyId", listKeywordParam.getClassifyId());
        paramMap.put("bookGroupId", listKeywordParam.getBookGroupId());
        PageBeanNew<ListKeywordVO> keywords = bookKeywordDao.listPageNew(pageParam, paramMap, "listKeywordsByClassify");
        if (keywords == null) {
            return new PageBeanNew<>(listKeywordParam.getCurrentPage(), listKeywordParam.getNumPerPage(), new ArrayList<>());
        }
        final List<Long> appIds = Lists.newArrayList();
        final List<Long> productIds = Lists.newArrayList();
        for (ListKeywordVO vo : keywords.getRecordList()) {
            if ("APP".equalsIgnoreCase(vo.getServeType())) {
                appIds.add(vo.getServeId());
            }
            if ("PRODUCT".equalsIgnoreCase(vo.getServeType())) {
                productIds.add(vo.getServeId());
            }
            if (vo.getIsEdit() == null) {
                vo.setIsEdit(1);
            }
        }
        Map<Long, AppDto> app = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(appIds)) {
            app = appConsr.mapBaseByIds(appIds);
        }
        Map<Long, ProductDto> proBasesByIds = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(productIds)) {
            proBasesByIds = productConsr.getProBasesByIds(productIds);
        }
        final BookGroupDTO dtoById = bookGroupDao.getDTOById(listKeywordParam.getBookGroupId());
        for (ListKeywordVO vo : keywords.getRecordList()) {
            if ("APP".equalsIgnoreCase(vo.getServeType())) {
                final AppDto appDto = app.get(vo.getServeId());
                if (null == appDto) {
                    continue;
                }
                vo.setChannelId(appDto.getChannelId());
                vo.setTypeCode(appDto.getTypeCode());
            }
            if ("PRODUCT".equalsIgnoreCase(vo.getServeType())) {
                final ProductDto productDto = proBasesByIds.get(vo.getServeId());
                if (null == productDto || null == productDto.getProductTypeDto()) {
                    continue;
                }
                vo.setChannelId(dtoById.getChannelId());
                vo.setTypeCode(productDto.getProductTypeDto().getTypeCode());
            }
        }
        return keywords;
    }

    @Override
    @ParamLog("根据关键词标识获取关键词基本信息")
    public KeywordVO getByBookKeyword(Long bookKeywordId) {
        KeywordVO keywordVO = bookKeywordDao.getByBookKeyword(bookKeywordId);
        return keywordVO;
    }

    @Override
    @ParamLog("获取5个关键词（改成10个了,20190911周磊改成不限制了，但是开发要求必须要加限制，所以先限制40个）")
    public List<KeywordDTO> listFiveKeyword(Long classifyId, Long bookGroupId) {
        //获取是否单独设置关键词
        List<KeywordDTO> keywords = bookKeywordDao.listFiveKeyword(classifyId, bookGroupId);
        if (ListUtils.isEmpty(keywords)) {
            keywords = bookKeywordDao.listFiveKeyword(0L, bookGroupId);
        }
        return keywords;
    }

    @Override
    @ParamLog("关键词消息回复")
    public void sendKeywordMessage(SendTextDTO sendTextDTO) {
        if (Objects.isNull(sendTextDTO)) {
            return;
        }
        if (SendMessageTypeEnum.GROUP.getCode().equals(sendTextDTO.getCode())) {
            this.sendKeywordMessageToGroup(sendTextDTO);
            return;
        }
        if (SendMessageTypeEnum.SELF.getCode().equals(sendTextDTO.getCode())) {
            dealBookGroupCipher(sendTextDTO);
            //判断是否为某个群分类名称
            inviteToGroupByKeyword(sendTextDTO);
            //智能机器人新版个人号回复
            dealSelfShortBookName(sendTextDTO);
            //回复关键词
            replySelfKeyword(sendTextDTO);
        }
    }

    @ParamLog("回复新版关键词")
    private void replySelfKeyword(SendTextDTO sendTextDTO) {
        String content = sendTextDTO.getTextContent();
        BookGroupCipherUser bookGroupCipherUser = bookGroupCipherUserDao.getByWxUserId(sendTextDTO.getWechatUserId());
        if (bookGroupCipherUser == null || StringUtil.isEmpty(bookGroupCipherUser.getShortBookName())) {
            return;
        }
        SelfRobotKeyword selfRobotKeyword = selfRobotKeywordDao.getByBookGroupIdAndKeyword(bookGroupCipherUser.getBookGroupId(), content);
        if (selfRobotKeyword != null) {
            sendSelfKeyword(selfRobotKeyword, sendTextDTO);
        } else {
            BookGroup bookGroup = bookGroupDao.getByShortBookName(content);
            if (bookGroup == null) {
                //既不是关键词也不是识别码
                String altIdAndWxId = sendTextDTO.getWxId() + "_" + sendTextDTO.getWechatUserId();
                Integer send = JedisClusterUtils.hgetJson2Class(REPLY_GUIDE_CACHE, altIdAndWxId, Integer.class);
                if (send == null) {
                    sendText(sendTextDTO, "请按以上指引回复准确的内容以便获取对应服务，谢谢！");
                    JedisClusterUtils.hset2Json(REPLY_GUIDE_CACHE, altIdAndWxId, 1);
                    //1小时缓存
                    JedisClusterUtils.expire(REPLY_GUIDE_CACHE, 60 * 60 * 1);
                }
            }
        }
    }

    @ParamLog("推送新版关键词回复消息")
    private void sendSelfKeyword(SelfRobotKeyword selfRobotKeyword, SendTextDTO sendTextDTO) {
        String userWxId = sendTextDTO.getWechatUserId();
        String ip = sendTextDTO.getIp();
        Integer code = sendTextDTO.getCode();
        String robotId = sendTextDTO.getWxId();
        Integer type = selfRobotKeyword.getType();
        if (ReplyTypeEnum.TEXT.value.equals(type)) {
            SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
            sendTextMessageVO.setContent(selfRobotKeyword.getContent());
            sendTextMessageVO.setAltId(robotId);
            sendTextMessageVO.setWxGroupId(userWxId);
            sendTextMessageVO.setIp(ip);
            sendTextMessageVO.setCode(code);
            WxGroupSDK.sendTextMessage(sendTextMessageVO);
        }
        if (ReplyTypeEnum.IMAGE.value.equals(type)) {
            SendPicMessageVO sendPicMessageVO = new SendPicMessageVO();
            sendPicMessageVO.setWxGroupId(userWxId);
            sendPicMessageVO.setAltId(robotId);
            sendPicMessageVO.setPicUrl(selfRobotKeyword.getPicUrl());
            sendPicMessageVO.setIp(ip);
            sendPicMessageVO.setCode(code);
            WxGroupSDK.sendPicMessage(sendPicMessageVO);
        }
        if (ReplyTypeEnum.LINK.value.equals(type)) {
            SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
            String content = selfRobotKeyword.getGuide() + "，点击这里进入：" + selfRobotKeyword.getLinkUrl();
            sendTextMessageVO.setContent(content);
            sendTextMessageVO.setAltId(robotId);
            sendTextMessageVO.setWxGroupId(userWxId);
            sendTextMessageVO.setIp(ip);
            sendTextMessageVO.setCode(code);
            WxGroupSDK.sendTextMessage(sendTextMessageVO);
        }
        if (ReplyTypeEnum.APP.value.equals(type)) {
            BookGroupDTO bookGroupDTO = bookGroupDao.getDTOById(selfRobotKeyword.getBookGroupId());
            AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(bookGroupDTO.getChannelId());
            if (AppAndProductTypeEnum.APP.value.equals(selfRobotKeyword.getServeType())) {
                AppDto appDto = appConsr.getBaseById(selfRobotKeyword.getServeId());
                if (appDto != null) {
                    accountSettingDto = qrcodeSceneConsr.getWechatInfo(appDto.getChannelId());
                }
            }
            // 处理链接地址
            String endUrl = selfRobotKeyword.getLinkUrl() + "&book_group_id=" + selfRobotKeyword.getBookGroupId() + "&wxId=" + userWxId;
            String linkUrl = SendWeixinRequestTools.splitUrl(accountSettingDto, endUrl);
            String resultUrl = UrlUtils.getShortUrl4Own(linkUrl);
            SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
            String content = selfRobotKeyword.getGuide() + "，点击这里进入：" + resultUrl;
            sendTextMessageVO.setContent(content);
            sendTextMessageVO.setAltId(robotId);
            sendTextMessageVO.setWxGroupId(userWxId);
            sendTextMessageVO.setIp(ip);
            sendTextMessageVO.setCode(code);
            WxGroupSDK.sendTextMessage(sendTextMessageVO);
        }
        if (ReplyTypeEnum.RESOURCE.value.equals(type)) {
            SendFileVO sendFileVO = new SendFileVO();
            Map<Long, ResourceDTO> map = resourceConsr.mapByIds(Arrays.asList(selfRobotKeyword.getResourceId()));
            ResourceDTO resourceDTO = map.get(selfRobotKeyword.getResourceId());
            if (resourceDTO != null) {
                sendFileVO.setFileUrl(resourceDTO.getFileUrl());
                sendFileVO.setFileName(resourceDTO.getResourceName());
            }
            sendFileVO.setIp(ip);
            sendFileVO.setAltId(robotId);
            sendFileVO.setWxId(userWxId);
            WxGroupSDK.sendFile(sendFileVO);
        }

    }

    @ParamLog("获取的关键词是否为社群书的简称")
    private void dealSelfShortBookName(SendTextDTO sendTextDTO) {
        String content = sendTextDTO.getTextContent();
        BookGroup bookGroup = bookGroupDao.getByShortBookName(content);
        if (bookGroup != null) {
            addBookGroupCipherUser(sendTextDTO, null, content, bookGroup.getId());
            dealBySelfRobot(sendTextDTO, bookGroup.getId(), bookGroup.getChannelId());
        } else {
            //判断之前是否有关联，如果没有，提示输入正确的识别码
            Long bookGroupId = bookGroupCipherUserDao.getBookGroupIdByWxUserId(sendTextDTO.getWechatUserId());
            if (bookGroupId == null) {
                String altIdAndWxId = sendTextDTO.getWxId() + "_" + sendTextDTO.getWechatUserId();
                Integer send = JedisClusterUtils.hgetJson2Class(REPLY_ERROR_SHORT_BOOK_NAME_CACHE, altIdAndWxId, Integer.class);
                if (send == null) {
                    sendText(sendTextDTO, "发送错误，请核对后重新发送。");
                    JedisClusterUtils.hset2Json(REPLY_ERROR_SHORT_BOOK_NAME_CACHE, altIdAndWxId, 1);
                    //1小时缓存
                    JedisClusterUtils.expire(altIdAndWxId, 60 * 60 * 1);
                }
            }
        }
    }

    @ParamLog("处理智能机器人个人号回复")
    private void dealBySelfRobot(SendTextDTO sendTextDTO, Long bookGroupId, Long channelId) {
        String text = "";
        List<SelfRobotKeyword> selfRobotKeywords = selfRobotKeywordDao.getListByBookGroupId(bookGroupId);
        if (!ListUtils.isEmpty(selfRobotKeywords)) {
            text = text + "识别码收到!我猜您有以下愿望：\n";
            Integer size = selfRobotKeywords.size();
            AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(channelId);

            for (int i = 0; i < size; i++) {
                SelfRobotKeyword selfRobotKeyword = selfRobotKeywords.get(i);
                String toAddIn = selfRobotKeyword.getGuide() + "，请回复“" + selfRobotKeyword.getKeyword() + "”\n";
                //最后一个
                if (i + 1 == size) {
                    // 拼接反馈链接
                    String feedbackUrl = "*common/C" + channelId + "/A0/feedback/suggest?bookGroupId="+bookGroupId+"&wxId=" + sendTextDTO.getWechatUserId();
                    String url = SendWeixinRequestTools.splitUrl(accountSettingDto, feedbackUrl);
                    toAddIn = toAddIn + "回复对应数字序号给我，我将助你达成所愿，提高读书效率。\n如有其他问题反馈，请点击链接：\n"
                            + UrlUtils.getShortUrl4Own(url);
                }
                String contents = text + toAddIn;
                if (contents.length() > LE) {
                    sendText(sendTextDTO, text);
                    text = toAddIn;
                } else {
                    text = contents;
                }
            }
        } else {
            text = text + "抱歉，本图书配套服务正在快马加鞭地赶来。服务到达时，会微信通知您。";
        }
        sendText(sendTextDTO, text);
    }

    @ParamLog("获取的关键词是否为社群书的暗号")
    private void dealBookGroupCipher(SendTextDTO sendTextDTO) {
        String cipher = sendTextDTO.getTextContent();
        //判断是否为加了随机码的暗号
        if (cipher.length() > 7) {
            cipher = cipher.substring(0, 7);
        }
        BookGroup bookGroup = bookGroupDao.getByBookGroupCipher(cipher);
        if (bookGroup != null) {
            try {
                addBookGroupCipherUser(sendTextDTO, cipher,null, bookGroup.getId());
                updateWxUserWechatRelevance(sendTextDTO);
                dealByBookGroup(sendTextDTO, bookGroup.getId(), false);
            } catch (Exception e) {
                log.error("拉群出错" + e.getMessage());
            }
        }
    }

    @ParamLog("更新系统微信用户和社群书微信用户关联表")
    private void updateWxUserWechatRelevance(SendTextDTO sendTextDTO) {
        if (sendTextDTO.getTextContent().length() != 15) {
            return;
        }
        String randomCode = sendTextDTO.getTextContent().substring(8);
        //更新
        wxUserWechatRelevanceDao.updateWxIdByRandomCode(randomCode, sendTextDTO.getWechatUserId());
    }

    @ParamLog("增加暗号对应书记录")
    private void addBookGroupCipherUser(SendTextDTO sendTextDTO, String cipher, String shortBookName, Long bookGroupId) {
        BookGroupCipherUser bookGroupCipherUser = new BookGroupCipherUser();
        bookGroupCipherUser.setBookGroupCipher(cipher);
        bookGroupCipherUser.setShortBookName(shortBookName);
        bookGroupCipherUser.setBookGroupId(bookGroupId);
        bookGroupCipherUser.setWxUserId(sendTextDTO.getWechatUserId());
        bookGroupCipherUser.setAltId(sendTextDTO.getWxId());
        //新增暗号对应记录
        bookGroupCipherUserDao.insert(bookGroupCipherUser);
    }

    @ParamLog("按照书处理暗号回复，推送资源")
    public void dealByBookGroup(SendTextDTO sendTextDTO, Long bookGroupId, Boolean isPushUpdate) {
        BookGroupDTO bookGroupDTO = bookGroupDao.getBookBaseInfoById(bookGroupId);
        String text = "";
        if (isPushUpdate != null && isPushUpdate) {
            text = text + "有更新！\n";
        }
        Boolean isInviteGroup = bookGroupDTO.getIsInviteGroup();
        // 获取配置的资源服务
        List<BookGroupServe> bookGroupServeList = bookGroupBiz.getBookGroupServeList(bookGroupId);
        String bookName = bookGroupDTO.getBookName();
        if (!ListUtils.isEmpty(bookGroupServeList)) {
            if (!StringUtil.isEmpty(bookName)) {
                text = text + "《" + bookName + "》" + "配有以下资源服务，点击链接立即获取：\n";
            }
            int i = 1;
            for (BookGroupServe bookGroupServe : bookGroupServeList) {
                if (i == 1 || i == 2) {
                    text = text + "🔥";
                }
                String toAdd = i + "." + bookGroupServe.getServeName() + "\n" + bookGroupServe.getShortUrl() + "\n";
                String content = text + toAdd;
                if (content.length() > LE) {
                    sendText(sendTextDTO, text);
                    text = toAdd;
                } else {
                    text = content;
                }
                i = i + 1;
            }
        } else {
            text = text + "《" + bookName + "》" + "还没有配置资源服务，敬请期待。\n";
        }
        //邀请进群
        if (isInviteGroup != null && isInviteGroup) {
            //获取社群码下的分类
            List<ListClassifyVO> listClassifyVOS = bookGroupClassifyBiz.listAllClassify(bookGroupId);
            if (!ListUtils.isEmpty(listClassifyVOS)) {
                String toAdd = "======================\n";
                String content = text + toAdd;
                if (content.length() > LE) {
                    sendText(sendTextDTO, text);
                    text = toAdd;
                } else {
                    text = content;
                }
                if (listClassifyVOS.size() == 1) {
                    ListClassifyVO listClassifyVO = listClassifyVOS.get(0);
                    //如果只有一个分类
                    //发送欢迎语
                    String toAdds = "☕本书还配有交流群“" + listClassifyVO.getClassify() + "”，" + listClassifyVO.getClassifyIntroduce() + "，点击下方邀请链接，即可进群";
                    String contents = text + toAdds;
                    if (contents.length() > LE) {
                        sendText(sendTextDTO, text);
                        text = toAdds;
                    } else {
                        text = contents;
                    }
                    sendText(sendTextDTO, text);
                    dealGroupInvite(sendTextDTO, listClassifyVO.getId(), listClassifyVO.getChangeNumber());
                } else {
                    String toAdds = "☕本书还配有以下交流群，选择你想加入的微信群，回复群名称，我会拉你入群！\n";
                    String inContents = text + toAdds;
                    if (inContents.length() > LE) {
                        sendText(sendTextDTO, text);
                        text = toAdds;
                    } else {
                        text = inContents;
                    }
                    for (ListClassifyVO listClassifyVO : listClassifyVOS) {
                        String toAddIn = "☑" + listClassifyVO.getClassify() + "：" + listClassifyVO.getClassifyIntroduce() + "\n";
                        String contents = text + toAddIn;
                        if (contents.length() > LE) {
                            sendText(sendTextDTO, text);
                            text = toAddIn;
                        } else {
                            text = contents;
                        }
                    }
                    sendText(sendTextDTO, text);
                }
                return;
            }
        }
        //发送配置的资源服务
        sendText(sendTextDTO, text);
    }

    @ParamLog("发送收到暗号后的本书介绍")
    private void sendText(SendTextDTO sendTextDTO, String content) {
        if (StringUtil.isEmpty(content)) {
            return;
        }
        String userWxId = sendTextDTO.getWechatUserId();
        String ip = sendTextDTO.getIp();
        Integer code = sendTextDTO.getCode();
        String robotId = sendTextDTO.getWxId();
        SendTextMessageVO vo = new SendTextMessageVO();
        vo.setContent(content);
        vo.setCode(code);
        vo.setWxId(robotId);
        vo.setAltId(robotId);
        vo.setWxGroupId(userWxId);
        vo.setIp(ip);
        SendSelfMsgTools.sendTextMessage(vo);
        log.info("发送收到暗号后的本书介绍 : {}", vo);
    }

    @ParamLog("分类群发送邀请入群链接")
    private void dealGroupInvite(SendTextDTO sendTextDTO, Long classifyId, Integer changeNumber) {
        //获取分类基本信息
        ClassifyVO classify = bookGroupClassifyDao.getClassify(classifyId);
        if (classify == null) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "分类不存在");
        }
        //获取第三套群，先判断这个小号是不是属于这个群的，如果不是，则切下一套
        String weixinGroupId = bookGroupClassifyBiz.getSelfGroup(classifyId, changeNumber, sendTextDTO.getWxId());
        if (StringUtil.isEmpty(weixinGroupId)) {
            throw new BookBizException(BookBizException.ID_NOT_EXIST, "群不存在classifyId=" + classifyId + ",changeNumber=" + changeNumber + ", wxId=" + sendTextDTO.getWxId());
        }
        sendAndCheckInviteGroup(sendTextDTO,weixinGroupId);
    }

    @ParamLog("判断冒泡和发送冒泡和发入群链接")
    private void sendAndCheckInviteGroup(SendTextDTO sendTextDTO, String wxGroupId) {
        if (checkLastAcTimeSendMsg(wxGroupId)) {
            //需要冒泡，冒泡之后隔3秒发
            ThreadPoolUtils.SEND_MAOPAO_THREAD_POOL.execute(() -> {
                sendMaoPao(sendTextDTO, wxGroupId);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    log.error("需要冒泡，冒泡之后隔3秒发出错！sendTextDTO=" + sendTextDTO.toString() + "wxGroupId=" + wxGroupId);
                }
                sendInviteToGroup(sendTextDTO, wxGroupId);
            });
        } else {
            //如果不需要冒泡，就直接发
            sendInviteToGroup(sendTextDTO, wxGroupId);
        }
    }

    @ParamLog("发送入群邀请链接之前先拿到群里最新的消息，如果不是48小时之内，就主动发一条消息")
    private Boolean checkLastAcTimeSendMsg(String wxGroupId) {
        Boolean flag = false;
        List<String> wechatGroupIds = new ArrayList<>();
        wechatGroupIds.add(wxGroupId);
        Map<String, Date> map = wechatGroupConsr.getChatLastTimeByGroup(wechatGroupIds);
        Date lastTime = map.get(wxGroupId);
        if (lastTime == null || (new Date().getTime() - lastTime.getTime()) > 48 * 60 * 60 * 1000) {
            flag = true;
        }
        return flag;
    }

    @ParamLog("发送冒泡消息")
    private void sendMaoPao(SendTextDTO sendTextDTO, String wxGroupId){
        SendTextMessageVO sendTextMessageVO = new SendTextMessageVO();
        sendTextMessageVO.setContent("我来冒个泡");
        sendTextMessageVO.setAltId(sendTextDTO.getWxId());
        sendTextMessageVO.setWxGroupId(wxGroupId);
        sendTextMessageVO.setIp(findIp(wxGroupId));
        WxGroupSDK.sendTextMessage(sendTextMessageVO);
        log.info("发送入群邀请链接之前发冒泡消息："+sendTextMessageVO.toString());
    }

    @ParamLog("发送进群链接")
    private void sendInviteToGroup(SendTextDTO sendTextDTO, String wxGroupId){
        SendGroupInviteVO sendGroupInviteVO = new SendGroupInviteVO();
        sendGroupInviteVO.setAltId(sendTextDTO.getWxId());
        sendGroupInviteVO.setWxId(sendTextDTO.getWechatUserId());
        sendGroupInviteVO.setWxGroupId(wxGroupId);
        sendGroupInviteVO.setIp(sendTextDTO.getIp());
        SendSelfMsgTools.sendGroupInvite(sendGroupInviteVO);
        log.info("[同意加好友发送欢迎语] 发送进群链接 sendGroupInviteVO：{}", sendGroupInviteVO);
    }

    @ParamLog("根据关键词判断关键词是否为1V1社群群名称")
    private void inviteToGroupByKeyword(SendTextDTO sendTextDTO) {
        String userWxId = sendTextDTO.getWechatUserId();
        //获取这个人最近一次触发的关联社群码
        BookGroupCipherUser bookGroupCipherUser = bookGroupCipherUserDao.getByWxUserId(userWxId);
        if (bookGroupCipherUser == null || StringUtil.isEmpty(bookGroupCipherUser.getBookGroupCipher())) {
            return;
        }
        List<BookGroupClassify> bookGroupClassifyList = bookGroupClassifyDao.getListByBookGroupId(bookGroupCipherUser.getBookGroupId());
        if (!ListUtils.isEmpty(bookGroupClassifyList)) {
            for (BookGroupClassify bookGroupClassify : bookGroupClassifyList) {
                if (bookGroupClassify.getClassify().equals(sendTextDTO.getTextContent())) {
                    //获取第三套群，先判断这个小号是不是属于这个群的，如果不是，则切下一套
                    String weixinGroupId = bookGroupClassifyBiz.getSelfGroup(bookGroupClassify.getId(), bookGroupClassify.getChangeNumber(), sendTextDTO.getWxId());
                    if (StringUtil.isEmpty(weixinGroupId)) {
                        throw new BookBizException(BookBizException.ID_NOT_EXIST, "群不存在classifyId=" + bookGroupClassify.getId() + ",changeNumber=" + bookGroupClassify.getChangeNumber() + ", wxId=" + sendTextDTO.getWxId());
                    }
                    sendAndCheckInviteGroup(sendTextDTO, weixinGroupId);
                }
            }
        }
    }

    private boolean insertBookKeywordRecord(String weixinGroupId, String userWxId, ReplyKeywordDTO replyKeywordDTO, GroupClassifyQrcodeDTO dto, String redisContent) {
        if (redisContent != null) {
            insertBookKeywordRecord(dto, replyKeywordDTO.getKeywordId(), userWxId, weixinGroupId, false);
            log.info("[关键词消息回复] redisContent:{} insertBookKeywordRecord return", redisContent);
            return true;
        } else {
            // 60s不回复同一关键词 20190916降低消息量方案之一
            JedisClusterUtils.setJson("BOOK:KEYWORD:" + weixinGroupId + "-" + replyKeywordDTO.getKeywordId(), replyKeywordDTO.getKeywordId(), 60);
            insertBookKeywordRecord(dto, replyKeywordDTO.getKeywordId(), userWxId, weixinGroupId, true);
        }
        return false;
    }

    /**
     * 原有的推送群关键词改为推送个人关键词
     */
    @ParamLog("群关键词消息回复")
    private void sendKeywordMessageToGroup(SendTextDTO sendTextDTO) {
        if (Objects.isNull(sendTextDTO)) {
            return;
        }
        final String content = sendTextDTO.getTextContent().trim();
        final String weixinGroupId = sendTextDTO.getWechatGroupId();
        String robotId = sendTextDTO.getWxId();
        //通过群id获取对应基本信息
        GroupClassifyQrcodeDTO classifyQrcodeInfo = bookGroupClassifyBiz.getClassifyQrcodeInfo(weixinGroupId);
        if (classifyQrcodeInfo == null) {
            log.info("[关键词消息回复] classifyQrcodeInfo is null");
            return;
        }
        //简单过滤非关键词的词
        if (StringUtil.isEmpty(content) || content.length() > 20) {
            return;
        }
        List<ReplyKeywordDTO> keywordDTOS = Lists.newArrayList();
        final boolean equals = "群主，来个抽奖".equals(content);
        if (equals) {
            ReplyKeywordDTO replyKeywordDTO = keywordDao.getByKeyword("群主，来个抽奖");
            keywordDTOS.add(replyKeywordDTO);
        } else {
            //获取匹配关键词 需求（1001903）by 20191023
            List<ReplyKeywordDTO> replyKeywordDTO = bookKeywordDao.listAllKeywordByClassifyIdAndBookGroupId(classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getBookGroupId());
            keywordDTOS.addAll(replyKeywordDTO);
        }
        if (CollectionUtils.isEmpty(keywordDTOS)) {
            log.info("[关键词消息回复] replyKeywordDTO is null");
            return;
        }
        // 去除被发送内容完整包含的关键词
        List<ReplyKeywordDTO> collect = keywordDTOS.stream().filter(x -> content.contains(x.getKeywords())).collect(Collectors.toList());
        if (ListUtils.isEmpty(collect)){
            log.info("[关键词消息回复] replyKeywordDTO is null");
            return;
        }
        //包含图片或文本的关键词回复
        List<ReplyKeywordDTO> ImgKeyword = keywordDTOS.stream()
                .filter(p -> (ReplyTypeEnum.IMAGE.value.equals(p.getReplyType()) || ReplyTypeEnum.TEXT.value.equals(p.getReplyType()))).collect(Collectors.toList());
        //不包含图片和文字且18点到9点 则合并关键词详情，其他情况走之前的模式
        if (CollectionUtils.isEmpty(ImgKeyword) && !DateUtils.isInBetweenTimes("09:00:00", "18:00:00")) {
            sendKeyWordAtPeak(collect, keywordDTOS, classifyQrcodeInfo, sendTextDTO);
        } else {
            // 组装发送关键词
            for (ReplyKeywordDTO dto : collect) {
                sendKeyword(sendTextDTO, dto, classifyQrcodeInfo);
            }
        }
    }

    @ParamLog("高峰期关键词发送")
    public void sendKeyWordAtPeak(List<ReplyKeywordDTO> replyKeyWords, List<ReplyKeywordDTO> keywordsAll, GroupClassifyQrcodeDTO classifyQrcodeInfo, SendTextDTO sendTextDTO) {
        final String ip = sendTextDTO.getIp();
        final Integer code = sendTextDTO.getCode();
        final String weixinGroupId = sendTextDTO.getWechatGroupId();
        final String userWxId = sendTextDTO.getWechatUserId();
        String robotId = sendTextDTO.getWxId();
        if (StringUtil.isBlank(robotId)) {
            log.info("[关键词消息回复] robotId is null :{}, robotId:{},weixinGroupId:{}", robotId, weixinGroupId);
            robotId = wechatGroupConsr.getRobotIdByGroupId(weixinGroupId);
        }
        //10min内不回复关键词
        String redisContent = JedisClusterUtils.getJson("BOOK:KEYWORD_PEAK:" + weixinGroupId, String.class);
        if (!StringUtil.isEmpty(redisContent)) {
            insertBookKeywordRecord(classifyQrcodeInfo, replyKeyWords.get(0).getKeywordId(), userWxId, weixinGroupId, false);
            return;
        } else {
            JedisClusterUtils.setJson("BOOK:KEYWORD_PEAK:" + weixinGroupId, weixinGroupId, 10 * 60);
            insertBookKeywordRecord(classifyQrcodeInfo, replyKeyWords.get(0).getKeywordId(), userWxId, weixinGroupId, true);
        }
        AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(classifyQrcodeInfo.getChannelId());
        StringBuilder sb = new StringBuilder();
        //目标关键词回复+文案
        combineKeyWord(replyKeyWords, classifyQrcodeInfo, accountSettingDto, sb);
        if (keywordsAll.size()>replyKeyWords.size()){
            sb.append("--------------------------------\n为避免晚间群消息干扰，10分钟内只响应一次关键词，请直接点击下面的链接，获取本群其他资源服务：\n\n");
            //剩余关键词回复
            for (ReplyKeywordDTO replyKeywordDTO : keywordsAll) {
                List<ReplyKeywordDTO> collect = replyKeyWords.stream().filter(x -> replyKeywordDTO.getKeywords().equals(x.getKeywords())).collect(Collectors.toList());
                if (!ListUtils.isEmpty(collect)){
                    continue;
                }
                List<ReplyKeywordDTO> addKeyWordList = new ArrayList<>();
                addKeyWordList.add(replyKeywordDTO);
                StringBuilder toAdd = combineKeyWord(addKeyWordList, classifyQrcodeInfo, accountSettingDto, new StringBuilder());
                StringBuilder content = sb.append(toAdd);
                if (content.length() > LE) {
                    replyKeywordDTO.setReplyType(ReplyTypeEnum.TEXT.value);
                    replyKeywordDTO.setContent(sb.toString());
                    SendWeixinRequestTools.sendKeywordMessage(replyKeywordDTO, robotId, weixinGroupId, ip, code);
                    sb = toAdd;
                } else {
                    sb = content;
                }
            }
        }
        ReplyKeywordDTO keywordDTO = replyKeyWords.get(0);
        keywordDTO.setReplyType(ReplyTypeEnum.TEXT.value);
        keywordDTO.setContent(sb.toString());
        SendWeixinRequestTools.sendKeywordMessage(keywordDTO, robotId, weixinGroupId, ip, code);

        for (ReplyKeywordDTO replyKeywordDTO : replyKeyWords) {
            //新增关键词触发记录
            addKeywordAppTouchRecord(replyKeywordDTO, weixinGroupId, classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getBookGroupId());
            //第一推送关键词消息埋点
            String keywordsKey = "BOOK:FIRSTKEYWORD:" + DateUtils.getShortDateStr() + "-" + weixinGroupId;
            Boolean isSend = JedisClusterUtils.getJson(keywordsKey, Boolean.class);
            if (isSend != null && isSend) {
                return;
            }
            JedisClusterUtils.setJson(keywordsKey, true);
            JedisClusterUtils.expire(keywordsKey, 86400);
            RobotReplyDTO robotReplyDTO = new RobotReplyDTO();
            robotReplyDTO.setKeyWord(sendTextDTO.getTextContent().trim());
            robotReplyDTO.setWxGroupId(weixinGroupId);
            robotReplyDTO.setWxUserId(userWxId);
            wechatGroupConsr.addFirstRobotReplyRecord(robotReplyDTO);
        }
    }

    /**
     *合并关键词回复
     */
    private StringBuilder combineKeyWord(List<ReplyKeywordDTO> keywordsAll, GroupClassifyQrcodeDTO classifyQrcodeInfo, AccountSettingDto accountSettingDto,StringBuilder sb) {
        for (ReplyKeywordDTO keyword : keywordsAll) {
            if (ReplyTypeEnum.LINK.value.equals(keyword.getReplyType()) || ReplyTypeEnum.APP.value.equals(keyword.getReplyType())) {
                String linkUrl = SendWeixinRequestTools.splitUrlNew(accountSettingDto, keyword.getLinkUrl(), classifyQrcodeInfo.getBookGroupId(), classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getGroupQrcodeId());
                sb.append(" ").append(keyword.getContent()).append("\n->").append(UrlUtils.getShortUrl4Own(linkUrl)).append("\n").append("\n");
            }
        }
        return sb;
    }

    /**
     * 发送关键词
     */
    private void sendKeyword(SendTextDTO sendTextDTO, ReplyKeywordDTO replyKeywordDTO, GroupClassifyQrcodeDTO classifyQrcodeInfo) {
        final String content = sendTextDTO.getTextContent().trim();
        final String weixinGroupId = sendTextDTO.getWechatGroupId();
        final String userWxId = sendTextDTO.getWechatUserId();
        final String ip = sendTextDTO.getIp();
        final Integer code = sendTextDTO.getCode();
        String robotId = sendTextDTO.getWxId();
        log.info("[关键词回复原始数据] ： sendKeywordMessage replyKeywordDTO ：{}, robotId:{}, weixinGroupId:{}", replyKeywordDTO, robotId, weixinGroupId);
        // 处理链接地址
        final boolean isApp = ReplyTypeEnum.APP.value.equals(replyKeywordDTO.getReplyType());
        final boolean isLink = ReplyTypeEnum.LINK.value.equals(replyKeywordDTO.getReplyType());
        if (isApp || isLink) {
            AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(classifyQrcodeInfo.getChannelId());
            String linkUrl = SendWeixinRequestTools.splitUrlNew(accountSettingDto, replyKeywordDTO.getLinkUrl(), classifyQrcodeInfo.getBookGroupId(), classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getGroupQrcodeId());
            String shortUrl4Own = UrlUtils.getShortUrl4Own(linkUrl);
            if (replyKeywordDTO.getLinkUrl().contains("live/C")) {
                // 获取直播课信息
                List<CourseListDto> list4BroadcastReminder = liveCons.getList4BroadcastReminder(replyKeywordDTO.getServeId(), replyKeywordDTO.getServeType());
                replyKeywordDTO.setReplyType(ReplyTypeEnum.TEXT.value);
                StringBuilder sb = new StringBuilder("【");
                sb.append(CollectionUtils.isEmpty(list4BroadcastReminder) ? replyKeywordDTO.getDescription() : list4BroadcastReminder.get(0).getTableTitle())
                        .append("】近期将开播的课程\n");
                if (!CollectionUtils.isEmpty(list4BroadcastReminder)) {
                    for (CourseListDto listDto : list4BroadcastReminder) {
                        sb.append("第").append(listDto.getSequenceNum()).append("课：").append(listDto.getTitle()).append("\n");
                    }
                }
                sb.append("查看更多课程表链接：").append(shortUrl4Own);
                replyKeywordDTO.setContent(sb.toString());
            }
            replyKeywordDTO.setLinkUrl(linkUrl);
            replyKeywordDTO.setShortLinkUrl(shortUrl4Own);
        }
        String redisContent = JedisClusterUtils.getJson("BOOK:KEYWORD:" + weixinGroupId + "-" + replyKeywordDTO.getKeywordId(), String.class);
        // 同一群10秒内不回复同一关键词，60s不回复同一关键词 20190916降低消息量方案之一
        if (insertBookKeywordRecord(weixinGroupId, userWxId, replyKeywordDTO, classifyQrcodeInfo, redisContent)) {
            return;
        }
        //获取推送消息机器人
        // 20190704改为收发一体
        if (StringUtil.isBlank(robotId)) {
            log.info("[关键词消息回复] robotId is null content:{}, robotId:{},weixinGroupId:{}", content, robotId, weixinGroupId);
            robotId = wechatGroupConsr.getRobotIdByGroupId(weixinGroupId);
        }
        log.info("[关键词回复发送数据] ： sendKeywordMessage replyKeywordDTO ：{}, robotId:{}, weixinGroupId:{}", replyKeywordDTO, robotId, weixinGroupId);
        SendWeixinRequestTools.sendKeywordMessage(replyKeywordDTO, robotId, weixinGroupId, ip, code);
        //新增关键词触发记录
        addKeywordAppTouchRecord(replyKeywordDTO, weixinGroupId, classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getBookGroupId());
        //第一推送关键词消息埋点
        String keywordsKey = "BOOK:FIRSTKEYWORD:" + DateUtils.getShortDateStr() + "-" + weixinGroupId;
        Boolean isSend = JedisClusterUtils.getJson(keywordsKey, Boolean.class);
        if (isSend != null && isSend) {
            return;
        }
        JedisClusterUtils.setJson(keywordsKey, true);
        JedisClusterUtils.expire(keywordsKey, 86400);
        RobotReplyDTO robotReplyDTO = new RobotReplyDTO();
        robotReplyDTO.setKeyWord(content);
        robotReplyDTO.setWxGroupId(weixinGroupId);
        robotReplyDTO.setWxUserId(userWxId);
        wechatGroupConsr.addFirstRobotReplyRecord(robotReplyDTO);
    }

    /**
     * 更新群人数
     */
    @Override
    public void updateGroupPeopleCount(String wxGroupId, Integer memberCount, GroupClassifyQrcodeDTO classifyQrcodeInfo) {
        Integer changeNumber = classifyQrcodeInfo.getChangeNumber();
        Long weixinQrcodeId = classifyQrcodeInfo.getWeixinQrcodeId();
        Long groupQrcodeId = classifyQrcodeInfo.getGroupQrcodeId();
        log.info("[更新群人数] updateGroupPeopleCount wxGroupId:{} memberCount:{} changeNumber：{} weixinQrcodeId：{} groupQrcodeId：{}", wxGroupId, memberCount, changeNumber, weixinQrcodeId, groupQrcodeId);
        if (Objects.isNull(memberCount) || StringUtil.isBlank(wxGroupId) || memberCount <= 0) {
            return;
        }
        String key = CacheConstant.BOOK + "groupPeopleCount:";
        String groupPeopleCount = JedisClusterUtils.hget(key, wxGroupId);
        log.info("[更新群人数] updateGroupPeopleCount groupPeopleCount:{}", groupPeopleCount);
        // 如果没有缓存或者有缓存但是人数与缓存不一致，代表有更新，则更新数据库
        final boolean update = StringUtil.isBlank(groupPeopleCount) || StringUtil.isNotBlank(groupPeopleCount) && !groupPeopleCount.equals(memberCount + "");
        if (update) {
            JedisClusterUtils.hset(key, wxGroupId, memberCount + "");
            // 将二维码改为已满群BookKeywordBizImpl
            Integer updatState = Optional.ofNullable(weixinQrcodeBiz.getGroupVersion(Collections.singletonList(wxGroupId))).map(x -> x.get(wxGroupId)).map(BookWxQrcodeDTO::getUpdateState).orElse(-1);
            if (memberCount >= changeNumber) {
                groupQrcodeDao.changeQrcodeState(groupQrcodeId, QrcodeStatusEnum.OVER_NUMBER.value);
                log.info("[更新群人数] 触发更新大于等于状态 wxGroupId:{} memberCount:{} changeNumber：{} weixinQrcodeId：{} groupQrcodeId：{}", wxGroupId, memberCount, changeNumber, weixinQrcodeId, groupQrcodeId);
            } else {
                // 二维码过期的数据不处理
                if (!UpdateStatusEnum.FIAL.value.equals(updatState)) {
                    groupQrcodeDao.changeQrcodeStateForNotOver(groupQrcodeId, QrcodeStatusEnum.ON_USE.value);
                    log.info("[更新群人数] 触发更新小于状态 wxGroupId:{} memberCount:{} changeNumber：{} weixinQrcodeId：{} groupQrcodeId：{}", wxGroupId, memberCount, changeNumber, weixinQrcodeId, groupQrcodeId);
                }
            }
            // 当群人数超过限制，或者群二维码更新状态为失败时更新群状态为满群
            boolean overstaff = memberCount >= (JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(classifyQrcodeInfo.getJoinGroupType()) ? 100 : 500);
            if (overstaff || UpdateStatusEnum.FIAL.value.equals(updatState)) {
                groupQrcodeBiz.changeToOverNumber(weixinQrcodeId, groupQrcodeId);
                log.info("[更新群人数] 触发更新满群状态 wxGroupId:{} memberCount:{} changeNumber：{} weixinQrcodeId：{} groupQrcodeId：{}", wxGroupId, memberCount, changeNumber, weixinQrcodeId, groupQrcodeId);
                groupQrcodeDao.changeQrcodeState(groupQrcodeId, QrcodeStatusEnum.OVER_NUMBER.value);
            } else {
                groupQrcodeBiz.changeToNotOverNumber(weixinQrcodeId, groupQrcodeId);
                log.info("[更新群人数] 触发更新未满群状态 wxGroupId:{} memberCount:{} changeNumber：{} weixinQrcodeId：{} groupQrcodeId：{}", wxGroupId, memberCount, changeNumber, weixinQrcodeId, groupQrcodeId);
            }
            groupQrcodeBiz.updateGroupCount(wxGroupId, memberCount);
            log.info("[成功更新群人数] updateGroupPeopleCount wxGroupId:{} memberCount:{}", wxGroupId, memberCount);
        }
    }

    /**
     * 修改群名称
     */
    @Override
    public void checkGroupName(String weixinGroupId, String groupName, String robotId, String ip) {
        log.info("[checkGroupName] weixinGroupId:{} groupName:{} robotId:{} ip:{} groupQrcodeDTO:{}", weixinGroupId, groupQrcodeDao, robotId, ip);
        if (StringUtil.isBlank(weixinGroupId) || StringUtil.isBlank(groupName) || StringUtil.isBlank(robotId) || StringUtil.isBlank(ip)) {
            return;
        }
        String key = CacheConstant.BOOK + "CHECKGROUPNAME:";
        String s = JedisClusterUtils.hget(key, weixinGroupId);
        log.info("[修改群名称] checkGroupName s:{}", s);
        if (StringUtil.isBlank(s)) {
            ChangeNameVO vo = new ChangeNameVO();
            vo.setName(groupName);
            vo.setAltId(robotId);
            vo.setWxGroupId(weixinGroupId);
            vo.setIp(ip);
            WxGroupSDK.changeGroupName(vo);
            // 改过名之后七天不再改名
            JedisClusterUtils.hset(key, weixinGroupId, "1");
            JedisClusterUtils.expire(key, 60 * 60 * 24 * 31);
            log.info("[修改群名称] checkGroupName vo:{}", vo);
        }
    }

    /**
     * 关键词应用触发记录
     */
    private void addKeywordAppTouchRecord(ReplyKeywordDTO replyKeywordDTO, String weixinGroupId, Long classifyId, Long bookGroupId) {
        Keyword keyword = keywordDao.getById(replyKeywordDTO.getKeywordId());
        if (keyword != null && ReplyTypeEnum.APP.value.equals(keyword.getReplyType())) {
            AppTouchRecord appTouchRecord = new AppTouchRecord();
            appTouchRecord.setServeId(keyword.getServeId());
            appTouchRecord.setServeType(keyword.getServeType());
            appTouchRecord.setTouchType(TouchTypeEnum.KEYWORD.value);
            appTouchRecord.setBookGroupId(bookGroupId);
            appTouchRecord.setClassifyId(classifyId);
            GroupQrcode groupQrcode = groupQrcodeDao.getGroupQrcodeByGroupId(weixinGroupId);
            if (groupQrcode != null) {
                appTouchRecord.setQrcodeId(groupQrcode.getId());
            }
            appTouchRecord.setWeixinGroupId(weixinGroupId);
            appTouchRecordDao.insert(appTouchRecord);
        }
    }

    private void insertBookKeywordRecord(GroupClassifyQrcodeDTO classifyQrcodeInfo, Long keywordId, String userWxId, String weixinGroupId, Boolean isSend) {
        BookKeywordRecord bookKeywordRecord = new BookKeywordRecord();
        BeanUtils.copyProperties(classifyQrcodeInfo, bookKeywordRecord);
        bookKeywordRecord.setKeywordId(keywordId);
        bookKeywordRecord.setUserWxId(userWxId);
        bookKeywordRecord.setWeixinGroupId(weixinGroupId);
        bookKeywordRecord.setSend(isSend);
        if (bookKeywordRecord.getGroupQrcodeId() == null) {
            GroupQrcode groupQr = groupQrcodeDao.getGroupQrcodeByGroupId(weixinGroupId);
            if (groupQr != null) {
                bookKeywordRecord.setGroupQrcodeId(groupQr.getId());
            }
        }
        bookKeywordRecordDao.insert(bookKeywordRecord);
    }

    @Override
    public PageBeanNew<KeywordStatisticsDTO> getKeywordStatistics(Integer currentPage, Integer numPerPage, Long bookGroupId, String weixinGroupId) {
        PageParam pageParam = new PageParam(currentPage, numPerPage);
        Map<String, Object> map = new HashMap<>();
        map.put("bookGroupId", bookGroupId);
        if (!StringUtil.isEmpty(weixinGroupId)) {
            GroupQrcode groupQrcode = groupQrcodeDao.getGroupQrcodeByGroupId(weixinGroupId);
            if (groupQrcode != null) {
                map.put("classifyId", groupQrcode.getClassifyId());
            }
        }
        //分页获取关键词，创建时间，名称信息
        PageBeanNew<KeywordStatisticsDTO> pageBeanNew = bookKeywordDao.listPageNew(pageParam, map, "getKeywordInfoByBookGroupId");
        List<KeywordStatisticsDTO> keywordStatisticsDTOS = pageBeanNew.getRecordList();
        if (ListUtils.isEmpty(keywordStatisticsDTOS)) {
            return pageBeanNew;
        }
        List<Long> keywordIds = keywordStatisticsDTOS.stream().filter(s -> s.getKeywordId() != null).map(KeywordStatisticsDTO::getKeywordId).collect(Collectors.toList());
        //获取关键词累计触发次数，最近一次触发时间
        List<KeywordStatisticsDTO> keywordStatisticsDTOSForOther = bookKeywordRecordDao.getKeywordStatistics(bookGroupId, weixinGroupId, keywordIds);
        Map<Long, KeywordStatisticsDTO> otherMap = new HashMap<>();
        if (!ListUtils.isEmpty(keywordStatisticsDTOSForOther)) {
            for (KeywordStatisticsDTO in : keywordStatisticsDTOSForOther) {
                otherMap.put(in.getKeywordId(), in);
            }
        }
        //获取最近7天的触发次数
        Date startDate = DateUtils.addDay(new Date(), -7);
        List<KeywordStatisticsDTO> keywordStatisticsDTOSForTime = bookKeywordRecordDao.getKeywordStatisticsByTime(bookGroupId, weixinGroupId, keywordIds, startDate);
        Map<Long, Integer> weekTouchCountMap = new HashMap<>();
        if (!ListUtils.isEmpty(keywordStatisticsDTOSForOther)) {
            for (KeywordStatisticsDTO in : keywordStatisticsDTOSForTime) {
                weekTouchCountMap.put(in.getKeywordId(), in.getWeekTouchCount());
            }
        }
        for (KeywordStatisticsDTO keywordStatisticsDTO : keywordStatisticsDTOS) {
            Long keywordId = keywordStatisticsDTO.getKeywordId();
            KeywordStatisticsDTO other = otherMap.get(keywordId);
            if (other == null) {
                //如果记录表里面没有就填充0
                keywordStatisticsDTO.setTouchCount(0);
                keywordStatisticsDTO.setWeekTouchCount(0);
                keywordStatisticsDTO.setAvgDayTouchCount(0D);
            } else {
                //计算，填充
                keywordStatisticsDTO.setTouchCount(other.getTouchCount());
                keywordStatisticsDTO.setLastTouchTime(other.getLastTouchTime());
                keywordStatisticsDTO.setWeekTouchCount(weekTouchCountMap.get(keywordId));
                Date createDate = keywordStatisticsDTO.getKeywordCreateDate();
                int days = (int) (DateUtils.getDayEnd(new Date()).getTime() - DateUtils.getDayEnd(createDate).getTime()) / 1000 / 60 / 60 / 24;
                if (days <= 0) {
                    days = 1;
                }
                Double avgTouchCount = (double) keywordStatisticsDTO.getTouchCount() / (double) days;
                keywordStatisticsDTO.setAvgDayTouchCount(new BigDecimal(avgTouchCount).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            }
        }
        return pageBeanNew;
    }

    @Override
    public Integer getKeywordCount(Long bookGroupId, Long classifyId) {
        if (bookGroupId == null) {
            throw new BookBizException(BookBizException.ERROR, "缺少参数bookGroupId");
        }
        return bookKeywordDao.getKeywordCount(bookGroupId, classifyId);
    }


    @Override
    public List<ServiceResourceDTO> getServiceByWeixinGroup(QrWeixinParam qrWeixinParam, Long classifyId, Long qrcodeId) {
        Map<String, Object> map = new HashMap<>();
        map.put("bookGroupId", qrWeixinParam.getBookGroupId());
        List<ServiceResourceDTO> serviceResourceDTOS = ResponesUtils.list(bookKeywordDao.listBy(map, "getServiceByWeixinGroup"), ServiceResourceDTO.class);
        if (ListUtils.isEmpty(serviceResourceDTOS)) {
            return new ArrayList<>();
        }
        for (ServiceResourceDTO serviceResourceDTO : serviceResourceDTOS) {
            AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(serviceResourceDTO.getChannelId());
            String linkUrl = SendWeixinRequestTools.splitUrlNew(accountSettingDto, serviceResourceDTO.getUrl(), qrWeixinParam.getBookGroupId(), classifyId, qrcodeId);
            serviceResourceDTO.setUrl(linkUrl);
        }
        List<Long> appIds = serviceResourceDTOS.stream().filter(s -> ("APP").equals(s.getTypeCode())).map(ServiceResourceDTO::getFromId).collect(Collectors.toList());
        Map<Long, AppDto> appMap = appConsr.getBaseByIds(appIds);
        if (!MapUtils.isEmpty(appMap)) {
            for (ServiceResourceDTO serviceResourceDTO : serviceResourceDTOS) {
                AppDto appDto = appMap.get(serviceResourceDTO.getFromId());
                if (appDto != null && serviceResourceDTO.getTypeCode().equals("APP")) {
                    serviceResourceDTO.setFromType(appDto.getTypeCode());
                    serviceResourceDTO.setTitle(appDto.getTitle());
                    serviceResourceDTO.setShortName(appDto.getTypeName());
                }
            }
        }
        List<Long> productIds = serviceResourceDTOS.stream().filter(s -> ("PRODUCT").equals(s.getTypeCode())).map(ServiceResourceDTO::getFromId).collect(Collectors.toList());
        Map<Long, ProductDto> productMap = productConsr.getProBasesByIds(productIds);
        if (!MapUtils.isEmpty(productMap)) {
            for (ServiceResourceDTO serviceResourceDTO : serviceResourceDTOS) {
                ProductDto productDto = productMap.get(serviceResourceDTO.getFromId());
                if (productDto != null && serviceResourceDTO.getTypeCode().equals("PRODUCT")) {
                    ProductTypeDto productTypeDto = productDto.getProductTypeDto();
                    if (productTypeDto != null) {
                        serviceResourceDTO.setFromType(productTypeDto.getTypeCode());
                        serviceResourceDTO.setTitle(productDto.getProductName());
                        serviceResourceDTO.setShortName(productTypeDto.getTypeName());
                    }
                }
            }
        }
        if (serviceResourceDTOS != null && !StringUtil.isEmpty(qrWeixinParam.getTypeCode()) && qrWeixinParam.getServeId() != null) {
            serviceResourceDTOS.removeIf(vo -> (qrWeixinParam.getTypeCode().equals(vo.getTypeCode()) && qrWeixinParam.getServeId().equals(vo.getFromId())));
        }
        List<ServiceResourceDTO> uniqueResources = serviceResourceDTOS.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getFromId() + ";" + o.getTypeCode()))), ArrayList::new)
        );
        return uniqueResources;
    }

    @Override
    public List<ServiceResourceDTO> getServiceByChannel(QrWeixinParam qrWeixinParam, Long wechatUserId) {
        QrWeixinParamVO qrWeixinParamVO = new QrWeixinParamVO();
        BeanUtils.copyProperties(qrWeixinParam, qrWeixinParamVO);
        List<MessageBookVO> messageBookVOS = ResponseHandleUtil.parseListResponse(qrcodeSceneService.getQrMessage4Book(qrWeixinParamVO, wechatUserId), MessageBookVO.class);
        return ResponesUtils.list(messageBookVOS, ServiceResourceDTO.class);
    }

    @ParamLog("根据社群码id获取关键词列表")
    @Override
    public List<KeywordDTO> getListByBookGroupId(Long bookGroupId) {
        return bookKeywordDao.getListByBookGroupId(bookGroupId);
    }

    @Override
    public ReplyKeywordDTO getReplyKeyword(String content, String weixinGroupId, String wexinGroupName) {
        ReplyKeywordDTO replyKeywordDTO = null;
        if (StringUtil.isEmpty(weixinGroupId) && StringUtil.isEmpty(wexinGroupName)) {
            return new ReplyKeywordDTO();
        }
        GroupClassifyQrcodeDTO classifyQrcodeInfo = null;
        if (!StringUtil.isEmpty(weixinGroupId)) {
            //通过群id获取对应基本信息
            classifyQrcodeInfo = bookGroupClassifyBiz.getClassifyQrcodeInfo(weixinGroupId);
        }
        if (classifyQrcodeInfo == null && !StringUtil.isEmpty(wexinGroupName)) {
            classifyQrcodeInfo = bookGroupClassifyDao.getClassifyQrcodeInfoByName((wexinGroupName));
        }
        if (classifyQrcodeInfo == null) {
            log.info("[关键词消息回复] classifyQrcodeInfo is null");
            return new ReplyKeywordDTO();
        }
        final boolean equals = "群主，来个抽奖".equals(content);
        if (equals) {
            replyKeywordDTO = keywordDao.getByKeyword("群主，来个抽奖");
        } else {
            //获取匹配关键词
            replyKeywordDTO = bookKeywordDao.getKeywordId(classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getBookGroupId(), content);
        }
        if (replyKeywordDTO == null) {
            return new ReplyKeywordDTO();
        }
        // 处理链接地址
        if (ReplyTypeEnum.APP.value.equals(replyKeywordDTO.getReplyType()) || ReplyTypeEnum.LINK.value.equals(replyKeywordDTO.getReplyType())) {
            AccountSettingDto accountSettingDto = qrcodeSceneConsr.getWechatInfo(classifyQrcodeInfo.getChannelId());
            String linkUrl = SendWeixinRequestTools.splitUrlNew(accountSettingDto, replyKeywordDTO.getLinkUrl(), classifyQrcodeInfo.getBookGroupId(), classifyQrcodeInfo.getClassifyId(), classifyQrcodeInfo.getGroupQrcodeId());
            replyKeywordDTO.setLinkUrl(linkUrl);
            if (!StringUtil.isEmpty(linkUrl)) {
                replyKeywordDTO.setShortLinkUrl(UrlUtils.getShortUrl4Own(linkUrl));
            }
        }
        return replyKeywordDTO;
    }

    @ParamLog("获取ip")
    private String findIp(String wechatGroupId) {
        Map<String, BookWxQrcodeDTO> groupVersion = weixinQrcodeBiz.getGroupVersion(Collections.singletonList(wechatGroupId));
        String ip = Optional.ofNullable(groupVersion.get(wechatGroupId)).orElse(new BookWxQrcodeDTO()).getWechatGroupIp();
        return ip;
    }
}
