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

import com.google.common.collect.Maps;

import com.pcloud.book.advertising.biz.AdvertisingSpaceBiz;
import com.pcloud.book.advertising.biz.GroupMasterTagBiz;
import com.pcloud.book.advertising.dto.QrcodeAdvertisingSpaceCountDTO;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.consumer.label.LabelConsr;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.consumer.user.AdviserConsr;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.group.biz.BookGroupBiz;
import com.pcloud.book.group.biz.BookGroupClassifyBiz;
import com.pcloud.book.group.biz.GroupAnnouncementBiz;
import com.pcloud.book.group.biz.GroupQrcodeBiz;
import com.pcloud.book.group.biz.WeixinQrcodeBiz;
import com.pcloud.book.group.constants.BookBusinessConstants;
import com.pcloud.book.group.dao.GroupQrcodeDao;
import com.pcloud.book.group.dto.AutoUpdateGroupNumDTO;
import com.pcloud.book.group.dto.BookWxQrcodeDTO;
import com.pcloud.book.group.dto.ChangeGroupNameDTO;
import com.pcloud.book.group.dto.GroupAndUserNumberDTO;
import com.pcloud.book.group.dto.GroupNameAndMaxSeqDTO;
import com.pcloud.book.group.dto.GroupQrcodeDTO;
import com.pcloud.book.group.dto.GroupQrcodeInfo4Advertising;
import com.pcloud.book.group.dto.GroupQrcodeInfoDTO;
import com.pcloud.book.group.dto.PushAddUserMessageDTO;
import com.pcloud.book.group.dto.QrcodeNameAndProIdDTO;
import com.pcloud.book.group.dto.WeixinQrcodeDTO;
import com.pcloud.book.group.entity.GroupQrcode;
import com.pcloud.book.group.enums.QrcodeStatusEnum;
import com.pcloud.book.group.tools.SendWeixinRequestTools;
import com.pcloud.book.group.vo.ClassifyQrcodeVO;
import com.pcloud.book.group.vo.ClassifyVO;
import com.pcloud.book.group.vo.GroupQrcodeBaseInfoVO;
import com.pcloud.book.group.vo.GroupQrcodeBookVO;
import com.pcloud.book.group.vo.ListGroupQrcodeResponseVO;
import com.pcloud.book.group.vo.ListQrcodeByClassifyParamVO;
import com.pcloud.book.group.vo.UpdateGroupQrcodeRequestVO;
import com.pcloud.book.keywords.dao.BookKeywordRecordDao;
import com.pcloud.book.keywords.dto.KeywordUserCountDTO;
import com.pcloud.book.mq.producer.BookMQProducer;
import com.pcloud.book.push.dao.PushGroupDao;
import com.pcloud.book.push.entity.PushGroup;
import com.pcloud.book.riddle.dto.GroupRiddleDTO;
import com.pcloud.book.util.common.ThreadPoolUtils;
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.ListUtils;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.usercenter.party.adviser.dto.AdviserBaseInfoDto;
import com.sdk.wxgroup.WxGroupSDK;

import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lily
 * @date 2019/4/18 15:31
 */
@Slf4j
@Component("groupQrcodeBiz")
public class GroupQrcodeBizImpl implements GroupQrcodeBiz {
    private static final Logger LOGGER = LoggerFactory.getLogger(GroupQrcodeBizImpl.class);
    @Autowired
    private GroupQrcodeDao groupQrcodeDao;
    @Autowired
    private BookGroupClassifyBiz bookGroupClassifyBiz;
    @Autowired
    private WeixinQrcodeBiz weixinQrcodeBiz;
    @Autowired
    private WechatGroupConsr wechatGroupConsr;
    @Autowired
    private BookMQProducer bookMQProducer;
    @Autowired
    private BookKeywordRecordDao bookKeywordRecordDao;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private GroupAnnouncementBiz groupAnnouncementBiz;
    @Autowired
    private PushGroupDao pushGroupDao;
    @Autowired
    private AdviserConsr adviserConsr;
    @Autowired
    private AdvertisingSpaceBiz advertisingSpaceBiz;
    @Autowired
    private LabelConsr labelConsr;
    @Autowired
    private BookGroupBiz bookGroupBiz;
    @Autowired
    private GroupMasterTagBiz groupMasterTagBiz;


    /**
     * 自动更新群人数线程是否开始执行
     */
//    private static final AtomicBoolean IS_START = new AtomicBoolean(false);


    /**
     * 处理群人数线程池
     */
//    private static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor();


    @Override
    public Integer updateGroupCount(String wxGroupId, Integer num) {
        return groupQrcodeDao.updateGroupCount(wxGroupId, num);
    }

    /**
     * 更新群人数线程
     */
//    private void updateGroupNum() {
//        // 若已开始则无需再启动
//        if(IS_START.get()) {
//            return;
//        }
//        // 若设置时已经为true则代表已经有线程执行成功
//        final boolean andSet = IS_START.getAndSet(true);
//        if (andSet) {
//            return;
//        }
//        SINGLE_THREAD_EXECUTOR.execute(() -> {
//            while (true) {
//                try{
//                    if (BookBusinessConstants.GROUP_NUM_DTO_MAP.size() < 1) {
//                        try {
//                            Thread.sleep(10000);
//                        } catch (InterruptedException e) {
//                            log.error("[updateGroupNum] InterruptedException:{}", e);
//                        }
//                        continue;
//                    }
//                    log.info("[更新群人数] start GROUP_NUM_DTO_MAP:{}", BookBusinessConstants.GROUP_NUM_DTO_MAP);
//                    for (Map.Entry<String, AutoUpdateGroupNumDTO> entry : BookBusinessConstants.GROUP_NUM_DTO_MAP.entrySet()) {
//                        final AutoUpdateGroupNumDTO value = entry.getValue();
//                        // 没到时间不执行（小于30s并且小于3个人不执行）
//                        final boolean b = null == value || ((System.currentTimeMillis() + 10) < value.getStartTime().getTime() && value.getNum().get() < 3);
//                        if(b) {
//                            log.info("[更新群人数] null == value:{}", entry);
//                            continue;
//                        }
//                        Integer peopleCounts = WxGroupSDK.getPeopleCounts(value.getWxGroupId(), value.getRobotId(), value.getIp());
//                        if (null == peopleCounts || peopleCounts < 1) {
//                            log.info("[更新群人数] null == peopleCounts || peopleCounts < 1 entry:{}; peopleCounts:{}", entry, peopleCounts);
//                            // 若未获取到将其移除
//                            BookBusinessConstants.GROUP_NUM_DTO_MAP.remove(entry.getKey());
//                            continue;
//                        }
//                        log.info("[更新群人数] entry:{}, peopleCounts:{}", entry, peopleCounts);
//                        groupQrcodeDao.updateUserNumber(value.getWxGroupId(), peopleCounts);
//                        BookBusinessConstants.GROUP_NUM_DTO_MAP.remove(entry.getKey());
//                        try {
//                            Thread.sleep(1000);
//                        } catch (InterruptedException e) {
//                            log.error("[updateGroupNum] InterruptedException:{}", e);
//                        }
//                    }
//                } catch (Exception e) {
//                    log.error("[updateGroupNum] : Exception:{}", e);
//                }
//                try {
//                    Thread.sleep(10000);
//                } catch (InterruptedException e) {
//                    log.error("[updateGroupNum] InterruptedException:{}", e);
//                }
//            }
//        });
//    }

    @Override
    public String getChangeGroupQrCode(Long classifyId) {
        log.info("[前端调用切群接口] getChangeGroupQrCode classifyId：{}", classifyId);
        if (Objects.isNull(classifyId)) {
            return StringUtil.EMPTY;
        }
        ClassifyVO classify = bookGroupClassifyBiz.getClassify(classifyId);
        if (Objects.isNull(classify)) {
            throw new BookBizException(BookBizException.ID_NOT_EXIST, "分类不存在");
        }
        List<ClassifyQrcodeVO> qrcodeByClassify = groupQrcodeDao.getQrcodeByClassifyId(classifyId);
        if (CollectionUtils.isEmpty(qrcodeByClassify)) {
            // 如果没有群则新增一个
            String url = changeGroupQrCode(classifyId);
            log.info("[前端调用切群接口] getChangeGroupQrCode 分类异常没有群 重新分配群classifyId：{} url:{}", classifyId, url);
            return url;
        }
        // 获取使用中的群
        List<ClassifyQrcodeVO> collect = qrcodeByClassify.stream().filter(p -> QrcodeStatusEnum.ON_USE.value.equals(p.getQrcodeState())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(collect)) {
            // 如果没有使用中群则新增一个
            String url = changeGroupQrCode(classifyId);
            log.info("[前端调用切群接口] getChangeGroupQrCode 没有使用中的群 重新分配群classifyId：{} url:{}", classifyId, url);
            return url;
        }
        if (collect.size() == 1) {
            ClassifyQrcodeVO qrcodeVO = collect.get(0);
            if (qrcodeVO.getUserNumber() < classify.getChangeNumber()) {
                return qrcodeVO.getQrcodeUrl();
            } else {
                //将二维码修改为已满群状态
                if (qrcodeVO.getUserNumber() >= 100) {
                    changeToOverNumber(qrcodeVO.getWeixinQrcodeId(), qrcodeVO.getId());
                }
                // 更新二维码状态
                groupQrcodeDao.changeQrcodeState(qrcodeVO.getId(), QrcodeStatusEnum.OVER_NUMBER.value);
                // 如果没有群则新增一个
                String url = changeGroupQrCode(classifyId);
                log.info("[前端调用切群接口] getChangeGroupQrCode 群超出切群人数了，但是没有切群 重新分配群classifyId：{} url:{}", classifyId, url);
                return url;
            }
        }
        String url = null;
        for (ClassifyQrcodeVO vo : collect) {
            if (vo.getUserNumber() >= classify.getChangeNumber()) {
                //将二维码修改为已满群状态
                if (vo.getUserNumber() >= 100) {
                    changeToOverNumber(vo.getWeixinQrcodeId(), vo.getId());
                }
                // 更新二维码状态
                groupQrcodeDao.changeQrcodeState(vo.getId(), QrcodeStatusEnum.OVER_NUMBER.value);
                log.info("[前端调用切群接口] getChangeGroupQrCode 处理超出了但是没有更新状态的群 vo:{}", vo);
            }
            if (vo.getUserNumber() < classify.getChangeNumber()) {
                url = vo.getQrcodeUrl();
            }
        }
        if (Objects.isNull(url)) {
            // 如果没有群则新增一个
            String qrcodeUrl = changeGroupQrCode(classifyId);
            log.info("[前端调用切群接口] getChangeGroupQrCode 没有可用群 重新分配群classifyId：{} url:{}", classifyId, url);
            return qrcodeUrl;
        }
        return url;
    }

    @Override
    public String changeGroupQrCode(Long classifyId) {
        return changeGroup(classifyId);
    }

    private String changeGroup(Long classifyId) {
        final String key = CacheConstant.BOOK + "changeGroup:" + classifyId;
        final String qrcodeKey = CacheConstant.BOOK + "changeGroupQrCode:" + classifyId;
        String url = StringUtil.EMPTY;
        final String threadId = Thread.currentThread().getId() + "";
        try {
            boolean getLock = JedisClusterUtils.setnx(key, threadId);
            if (getLock) {
                JedisClusterUtils.expire(key, 3);
                // 双重校验避免前一个事务未提交
                String qrcode = JedisClusterUtils.get(qrcodeKey);
                if (StringUtil.isNotBlank(qrcode)) {
                    return qrcode;
                }
                // 如果没有群则新增一个
                url = addWechatGroup(classifyId, null);
                log.info("[直接切群] changeGroupQrCode 直接切群classifyId：{} url:{}", classifyId, url);
                // 切群之后将新切群放入缓存5分钟，5分钟内若需要切群则直接从缓存中获取，避免事务未提交，双重判断
                JedisClusterUtils.set(qrcodeKey, url, 60 * 5);
            } else {
                return url;
            }
        } finally {
            String s = JedisClusterUtils.get(key);
            if(StringUtil.isNotBlank(s) && s.contains(threadId)) {
                JedisClusterUtils.del(key);
            }
        }
        return url;
    }

    @Override
    @ParamLog("updateGroupQrcode")
    public void updateGroupQrcode(UpdateGroupQrcodeRequestVO vo) {
        this.groupQrcodeDao.updateGroupQrcode(vo.getGroupQrcodeId(), vo.getQrcodeUrl(), vo.getUserId());
    }

    @Override
    @ParamLog("listAllGroupQrcode")
    public PageBeanNew<ListGroupQrcodeResponseVO> listAllGroupQrcode(String wxGroupName, Integer currentPage, Integer numPerPage) {
        PageParam pageParam = new PageParam(currentPage, numPerPage);
        final Map<String, Object> map = Maps.newHashMap();
        map.put("groupName", StringUtil.isEmpty(wxGroupName) ? null : wxGroupName);
        final PageBeanNew<ListGroupQrcodeResponseVO> groupQrcode = this.groupQrcodeDao.listPageNew(pageParam, map, "listAllGroupQrcode");
        if (null == groupQrcode || CollectionUtils.isEmpty(groupQrcode.getRecordList())) {
            return groupQrcode;
        }
        final List<Long> adviserIds = groupQrcode.getRecordList().stream().map(ListGroupQrcodeResponseVO::getAdviserId).distinct().collect(Collectors.toList());
        final Map<Long, String> names = adviserConsr.getNames(adviserIds);
        for (ListGroupQrcodeResponseVO vo : groupQrcode.getRecordList()) {
            vo.setAdviserName(names.get(vo.getAdviserId()));
        }
        return groupQrcode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ParamLog("新增群二维码")
    public Long insert(GroupQrcode groupQrcode) {
        groupQrcodeDao.insert(groupQrcode);
        //判断广告位标记
        groupMasterTagBiz.addTagByBookGroup(groupQrcode.getClassifyId(), groupQrcode.getId());
        return groupQrcode.getId();
    }

    @Override
    @ParamLog("根据分类删除二维码")
    public void deleteByClassifyId(Long classifyId) {
        groupQrcodeDao.deleteByClassifyId(classifyId);
    }

    @Override
    @ParamLog("获取群用户")
    public Map<Long, GroupAndUserNumberDTO> listGroupAndUserNumber(List<Long> classifyIds) {
        return groupQrcodeDao.listGroupAndUserNumber(classifyIds);
    }

    @Override
    @ParamLog("获取分类下的二维码")
    public PageBeanNew<ClassifyQrcodeVO> listQrcodeByClassify(ListQrcodeByClassifyParamVO listQrcodeByClassifyParamVO) {
        PageParam pageParam = new PageParam(listQrcodeByClassifyParamVO.getCurrentPage(), listQrcodeByClassifyParamVO.getNumPerPage());
        //获取分类基本信息
        ClassifyVO classify = bookGroupClassifyBiz.getClassify(listQrcodeByClassifyParamVO.getClassifyId());
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("classifyId", listQrcodeByClassifyParamVO.getClassifyId());
        paramMap.put("changeNumber", classify.getChangeNumber());
        //获取二维码列表
        PageBeanNew<ClassifyQrcodeVO> pageBeanNew = groupQrcodeDao.listPageNew(pageParam, paramMap, "listQrcodeByClassify");
        if (pageBeanNew == null || pageBeanNew.getRecordList() == null) {
            return new PageBeanNew<>(listQrcodeByClassifyParamVO.getCurrentPage(), listQrcodeByClassifyParamVO.getNumPerPage(), new ArrayList<>());
        }
        //设置退群率
        setQuitRate(pageBeanNew.getRecordList());
        //设置使用关键词次数
        setKeywordCount(pageBeanNew.getRecordList());
        return pageBeanNew;
    }

    @Override
    public List<ClassifyQrcodeVO> getQrcodeByClassify(Long bookGroupId, Long classifyId) {
        List<ClassifyQrcodeVO> qrcodeByClassify = groupQrcodeDao.getQrcodeByClassify(classifyId);
        if (ListUtils.isEmpty(qrcodeByClassify)){
            return new ArrayList<>();
        }
        return qrcodeByClassify;
    }

    @ParamLog(value = "设置关键词次数", isBefore = false)
    private void setKeywordCount(List<ClassifyQrcodeVO> classifyQrcodeVOS) {
        if (ListUtils.isEmpty(classifyQrcodeVOS)) {
            return;
        }
        List<Long> qrcodeIds = new ArrayList<>();
        for (ClassifyQrcodeVO classifyQrcodeVO : classifyQrcodeVOS) {
            qrcodeIds.add(classifyQrcodeVO.getWeixinQrcodeId());
        }
        if (ListUtils.isEmpty(qrcodeIds)) {
            return;
        }
        Map<Long, KeywordUserCountDTO> keywordMap = bookKeywordRecordDao.listKeywordUseCount(qrcodeIds);
        for (ClassifyQrcodeVO classifyQrcodeVO : classifyQrcodeVOS) {
            if (keywordMap == null || keywordMap.get(classifyQrcodeVO.getWeixinQrcodeId()) == null) {
                classifyQrcodeVO.setKeywordCount(0);
            } else {
                KeywordUserCountDTO keywordUserCountDTO = keywordMap.get(classifyQrcodeVO.getWeixinQrcodeId());
                classifyQrcodeVO.setKeywordCount(keywordUserCountDTO == null ? 0 : keywordUserCountDTO.getUseCount());
            }
          
        }
    }

    @ParamLog(value = "设置退群率", isBefore = false)
    private void setQuitRate(List<ClassifyQrcodeVO> classifyQrcodeVOS) {
        if (ListUtils.isEmpty(classifyQrcodeVOS)) {
            return;
        }
        List<String> weixinGroupIds = new ArrayList<>();
        for (ClassifyQrcodeVO classifyQrcodeVO : classifyQrcodeVOS) {
            weixinGroupIds.add(classifyQrcodeVO.getWeixinGroupId());
        }
        //获取退群率
        Map<String, BigDecimal> rateMap = wechatGroupConsr.mapOutGroupRate(weixinGroupIds);
        for (ClassifyQrcodeVO classifyQrcodeVO : classifyQrcodeVOS) {
            classifyQrcodeVO.setQuitRate(rateMap == null || rateMap.get(classifyQrcodeVO.getWeixinGroupId()) == null ? new BigDecimal(0) : rateMap.get(classifyQrcodeVO.getWeixinGroupId()));
        }
    }

    @Override
    @ParamLog("修改群名称")
    public void modifyWechatGroupName(String wechatGroupName, Long id, Long updateUser) {
        if (wechatGroupName == null) {
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "微信群名称不能为空");
        }
        ChangeGroupNameDTO changeGroupNameDTO = groupQrcodeDao.getUpdateGroupNameParam(id);
        groupQrcodeDao.modifyNameById(wechatGroupName, id, updateUser);
        if (changeGroupNameDTO != null) {
            //获取修改群名称小号
            final String wechatGroupId = changeGroupNameDTO.getWxGroupId();
            String robotId = wechatGroupConsr.getRobotIdByGroupId(wechatGroupId);
            Map<String, BookWxQrcodeDTO> groupVersion = weixinQrcodeBiz.getGroupVersion(Collections.singletonList(wechatGroupId));
            String ip = Optional.ofNullable(groupVersion.get(wechatGroupId)).orElse(new BookWxQrcodeDTO()).getWechatGroupIp();
            SendWeixinRequestTools.changeGroupName(robotId, changeGroupNameDTO.getWxGroupId(), wechatGroupName, ip);
        }
    }

    @Override
    @ParamLog("新增一个用户")
    public void addOneUser(String weixinGroupId, Integer memberCount, String nickName, String robotId, String ip) {
        // 收发一体
        String robotIdByGroupId = robotId;
        if(StringUtil.isBlank(robotId)) {
            log.info("[新增一个用户] : robotId is null weixinGroupId:{},memberCount:{},nickName:{},robotId:{}", weixinGroupId, memberCount, nickName, robotId);
            robotIdByGroupId = wechatGroupConsr.getRobotIdByGroupId(weixinGroupId);
        }
//        if(robotIdByGroupId != null){
//            Integer peopleCounts = WxGroupSDK.getPeopleCounts(weixinGroupId, robotIdByGroupId, ip);
//            if (peopleCounts != null) {
//                memberCount = peopleCounts;
//            }
//        }
        //获取群基本信息
        GroupQrcodeDTO groupQrcodeDTO = groupQrcodeDao.getGroupQrcodeInfo(weixinGroupId);
        log.info("[新增一个用户] groupQrcodeDTO:{}", groupQrcodeDTO);
        if (groupQrcodeDTO == null) {
            return;
        }
        //更新用户数（由于微信有延迟及时更新可能会数据对不上，所以调用方法延迟30s，统一处理）
        // 发消息时获取的群人数更准确memberCount 20190905
//        AutoUpdateGroupNumDTO numDTO = BookBusinessConstants.GROUP_NUM_DTO_MAP.get(weixinGroupId);
//        if (null == numDTO){
//            numDTO = new AutoUpdateGroupNumDTO(weixinGroupId, robotId, ip, new Date());
//        } else {
//            numDTO.getNum().incrementAndGet();
//            numDTO.setRobotId(robotId);
//            numDTO.setIp(ip);
//            numDTO.setWxGroupId(weixinGroupId);
//            numDTO.setStartTime(new Date());
//        }
//        BookBusinessConstants.GROUP_NUM_DTO_MAP.put(weixinGroupId, numDTO);
        // 启动更新群人数线程
//        if (!IS_START.get()) {
//            this.updateGroupNum();
//        }
        // 新用户进群时系统消息群人数不准，所以从系统中取然后+1，更新群人数操作会在群消息地方处理
        memberCount = groupQrcodeDTO.getUserNumber() + 1;
        //如果人数超过限制，重新分配群
        if (memberCount >= groupQrcodeDTO.getChangeNumber() && QrcodeStatusEnum.ON_USE.value.equals(groupQrcodeDTO.getQrcodeState())) {
            //修改状态，重新分配一个群
            addWechatGroup(groupQrcodeDTO.getClassifyId(), groupQrcodeDTO.getId());
        }
        if (memberCount >= 100 && QrcodeStatusEnum.ON_USE.value.equals(groupQrcodeDTO.getUseState())) {
            //将二维码修改为已满群状态
            changeToOverNumber(groupQrcodeDTO.getWeixinQrcodeId(), groupQrcodeDTO.getId());
        }

        Map<String, Integer> nickNames = JedisClusterUtils.getJson("BOOK:WEIXINGROUP:GUIDEUSER" + weixinGroupId, Map.class);
        if (nickNames == null) {
            nickNames = new HashMap<>();
            nickNames.put(nickName, 0);
        } else {
            nickNames.put(nickName, 0);
        }
        LOGGER.info("新用户"+nickNames);
        JedisClusterUtils.setJson("BOOK:WEIXINGROUP:GUIDEUSER" + weixinGroupId, nickNames, 600);

        String value = JedisClusterUtils.getJson("BOOK:WEIXINGROUP:GUIDE" + weixinGroupId, String.class);

        if (StringUtil.isEmpty(value)) {
            JedisClusterUtils.setJson("BOOK:WEIXINGROUP:GUIDE" + weixinGroupId, weixinGroupId, 5);
        } else {
            return;
        }
        LOGGER.info("【发送欢迎语消息】，topic发送开始");
        PushAddUserMessageDTO pushAddUserMessageDTO = new PushAddUserMessageDTO();
        pushAddUserMessageDTO.setWeixinGroupId(weixinGroupId);
        pushAddUserMessageDTO.setTime(System.currentTimeMillis());
        pushAddUserMessageDTO.setNickName(nickName);
        pushAddUserMessageDTO.setMemberCount(memberCount);
        pushAddUserMessageDTO.setRobotId(robotIdByGroupId);
        pushAddUserMessageDTO.setIp(ip);
        bookMQProducer.pushAddUserMessageTopic(pushAddUserMessageDTO);
        LOGGER.info("【发送欢迎语消息】，topic发送结束");
    }


    @Override
    @ParamLog("获取群二维码相关信息")
    public Map<Long, GroupQrcodeInfoDTO> listQrcodeInfoByIds(List<Long> groupQrcodeIds) {
        return groupQrcodeDao.listQrcodeInfoByIds(groupQrcodeIds);
    }

    @Override
    public GroupQrcodeBaseInfoVO getBaseById(Long groupQrcodeId) {
        return groupQrcodeDao.getBaseById(groupQrcodeId);
    }

    @Override
    public void updateUserNumber(String weixinGroupId, String wxUserId) {
        if (StringUtil.isEmpty(weixinGroupId) || StringUtil.isEmpty(wxUserId)) {
            return;
        }
        final Map<String, BookWxQrcodeDTO> groupVersion = weixinQrcodeBiz.getGroupVersion(Collections.singletonList(weixinGroupId));
        Integer peopleCounts = WxGroupSDK.getPeopleCounts(weixinGroupId, wxUserId, Optional.ofNullable(groupVersion.get(weixinGroupId)).orElse(new BookWxQrcodeDTO()).getWechatGroupIp());
        if (peopleCounts != null) {
            //更新用户数
            groupQrcodeDao.updateUserNumber(weixinGroupId, peopleCounts);
            GroupQrcode groupQrcode = groupQrcodeDao.getGroupQrcodeByGroupId(weixinGroupId);
            if (null != groupQrcode) {
                //更新广告曝光量
                advertisingSpaceBiz.updateExposureByQrcode(groupQrcode.getId(), peopleCounts);
            }
        }
    }

    @Override
    public Map<String, GroupQrcodeInfo4Advertising> listGroupQrcodeInfo4Advertising(List<String> wxGroupIds) {
        Map<String, GroupQrcodeInfo4Advertising> resultMap = new HashMap<>();
        List<GroupQrcodeInfo4Advertising> advertisingList = groupQrcodeDao.getGroupInfo4AdvertisingByWxGroupIds(wxGroupIds);
        if (ListUtils.isEmpty(advertisingList)) {
            return new HashMap<>();
        }
        List<Long> adviserIds = advertisingList.stream().filter(s -> s.getAdviserId() != null).map(GroupQrcodeInfo4Advertising::getAdviserId).distinct().collect(Collectors.toList());
        List<Long> qrcodeIds = advertisingList.stream().filter(s -> s.getGroupQrcodeId() != null).map(GroupQrcodeInfo4Advertising::getGroupQrcodeId).distinct().collect(Collectors.toList());
        List<Long> labelIds = new ArrayList<>();
        List<Long> proLabels = advertisingList.stream().filter(s -> s.getProLabelId() != null).map(GroupQrcodeInfo4Advertising::getProLabelId).distinct().collect(Collectors.toList());
        List<Long> depLabels = advertisingList.stream().filter(s -> s.getDepLabelId() != null).map(GroupQrcodeInfo4Advertising::getDepLabelId).distinct().collect(Collectors.toList());
        List<Long> purLabels = advertisingList.stream().filter(s -> s.getPurLabelId() != null).map(GroupQrcodeInfo4Advertising::getPurLabelId).distinct().collect(Collectors.toList());
        if (!ListUtils.isEmpty(proLabels)) {
            labelIds.addAll(proLabels);
        }
        if (!ListUtils.isEmpty(depLabels)) {
            labelIds.addAll(depLabels);
        }
        if (!ListUtils.isEmpty(purLabels)) {
            labelIds.addAll(purLabels);
        }
        //关闭广告位的出版社
        List<Long> closeAgentIds = advertisingSpaceBiz.getCloseAgentId();
        //出版社信息
        Map<Long, AdviserBaseInfoDto> baseInfoDtoMap = new HashMap<>();
        Map<Long, String> adviserNameMap = new HashMap<>();
        //获取广告位数量
        Map<Long, QrcodeAdvertisingSpaceCountDTO> advertisingSpaceNumMap = new HashMap<>();
        //标签
        Map<Long, String> labelMap = new HashMap<>();
        if (!ListUtils.isEmpty(adviserIds)) {
            baseInfoDtoMap = adviserConsr.getAdviserId2AdviserInfoDtoMap(adviserIds);
            adviserNameMap = adviserConsr.getNames(adviserIds);
        }
        if (!ListUtils.isEmpty(qrcodeIds)) {
            advertisingSpaceNumMap = advertisingSpaceBiz.mapAdvertisingSpaceNum(qrcodeIds);
        }

        if (!ListUtils.isEmpty(labelIds)) {
            labelMap = labelConsr.getLabelName(labelIds);
        }
        for (GroupQrcodeInfo4Advertising advertising : advertisingList) {
            if (!MapUtils.isEmpty(baseInfoDtoMap) && null != advertising.getAdviserId()) {
                AdviserBaseInfoDto adviserBaseInfoDto = baseInfoDtoMap.get(advertising.getAdviserId());
                if (null != adviserBaseInfoDto) {
                    advertising.setAgentId(adviserBaseInfoDto.getAgentId());
                    advertising.setAgentName(adviserBaseInfoDto.getAgentName());
                }
            }
            if (!MapUtils.isEmpty(adviserNameMap) && null != advertising.getAdviserId()) {
                advertising.setAdviserName(adviserNameMap.get(advertising.getAdviserId()));
            }
            if (!ListUtils.isEmpty(closeAgentIds) && null != advertising.getAgentId()) {
                if (closeAgentIds.contains(advertising.getAgentId())) {
                    advertising.setOpen(false);
                }
            }
            if (!MapUtils.isEmpty(advertisingSpaceNumMap) && null != advertising.getGroupQrcodeId()) {
                QrcodeAdvertisingSpaceCountDTO dto = advertisingSpaceNumMap.get(advertising.getGroupQrcodeId());
                if (null != dto) {
                    advertising.setAdvertisingSpaceNum(dto.getAdvertisingSpaceNum());
                }
            }
            if (!MapUtils.isEmpty(labelMap)) {
                if (null != advertising.getProLabelId() && labelMap.containsKey(advertising.getProLabelId())) {
                    advertising.setProLabelName(labelMap.get(advertising.getProLabelId()));
                }
                if (null != advertising.getDepLabelId() && labelMap.containsKey(advertising.getDepLabelId())) {
                    advertising.setDepLabelName(labelMap.get(advertising.getDepLabelId()));
                }
                if (null != advertising.getPurLabelId() && labelMap.containsKey(advertising.getPurLabelId())) {
                    advertising.setPurLabelName(labelMap.get(advertising.getPurLabelId()));
                }
            }
            resultMap.put(advertising.getWxGroupId(), advertising);
        }
        return resultMap;
    }

    /**
     * 重新分配一个群
     */
    @ParamLog("重新分配一个群")
    @Transactional(rollbackFor = Exception.class)
    public String addWechatGroup(Long classifyId, Long groupQrcodeId) {
        Integer generation = null;
        ClassifyVO classifyVOOne = bookGroupClassifyBiz.getClassify(classifyId);
        if (classifyVOOne != null && classifyVOOne.getBookGroupId() != null) {
            QrcodeNameAndProIdDTO qrcodeNameAndProId = bookGroupBiz.getQrcodeNameAndProId(classifyVOOne.getBookGroupId());
            if (qrcodeNameAndProId != null && new Integer(2).equals(qrcodeNameAndProId.getJoinGroupType())) {
                generation = 3;
            }
        }
        WeixinQrcodeDTO oneQrcode = weixinQrcodeBiz.getOneQrcode(generation);
        log.info("[重新分配一个群] : oneQrcode:{}", oneQrcode);
        if (oneQrcode != null) {
            //将二维码改为已满群状态
            Integer number = 0;
            if (!Objects.isNull(groupQrcodeId)) {
                number = groupQrcodeDao.changeQrcodeState(groupQrcodeId, QrcodeStatusEnum.OVER_NUMBER.value);
            }
            log.info("[重新分配一个群] : groupQrcodeDao.changeQrcodeState  number:{}", number);
            // 当该分类不存在群的时候分配一个
            if (number > 0 || null == groupQrcodeId){
                //获取标签对应基本信息
                GroupNameAndMaxSeqDTO groupNameAndMaxSeqDTO = bookGroupClassifyBiz.getGroupNameAndMaxSeq(classifyId);
                log.info("[重新分配一个群] : groupNameAndMaxSeqDTO:{}", groupNameAndMaxSeqDTO);
                if (groupNameAndMaxSeqDTO != null) {
                    Integer maxSeq = groupNameAndMaxSeqDTO.getMaxSeq() + 1;
                    String groupName = groupNameAndMaxSeqDTO.getGroupQrcodeName() + groupNameAndMaxSeqDTO.getClassify() + maxSeq + "群";
                    // 群长度超过16部分会被截取，导致群名称重复
                    if (groupName.length() > 15) {
                        final String s = maxSeq + "群";
                        groupName = groupNameAndMaxSeqDTO.getClassify() + s;
                        if (groupName.length() > 15) {
                            groupName = groupNameAndMaxSeqDTO.getClassify().substring(0, 15 - s.length()) + s;
                        }
                    }
                    GroupQrcode groupQrcode = new GroupQrcode();
                    groupQrcode.setWeixinGroupId(oneQrcode.getWeixinGroupId());
                    groupQrcode.setQrcodeUrl(oneQrcode.getQrcodeUrl());
                    groupQrcode.setCreateUser(groupNameAndMaxSeqDTO.getCreateUser());
                    groupQrcode.setWeixinQrcodeId(oneQrcode.getId());
                    groupQrcode.setGroupSeq(maxSeq);
                    groupQrcode.setQrcodeHeadUrl(readerConsr.getNineHeadUrl());
                    groupQrcode.setUserNumber(oneQrcode.getUserNumber());
                    groupQrcode.setGroupName(groupName);
                    groupQrcode.setClassifyId(classifyId);
                    this.insert(groupQrcode);
                    ThreadPoolUtils.SEND_MESSAGE_THREAD_POOL.execute(()->{
                        //获取该社群书下是否有群公告
                        ClassifyVO classifyVO = bookGroupClassifyBiz.getClassify(classifyId);
                        groupAnnouncementBiz.setAnForGroup(classifyVO.getBookGroupId(), classifyId, oneQrcode.getWeixinGroupId());
                        //补充该分类下的群发关联
                        List<PushGroup> pushGroups = pushGroupDao.getListByClassifyId(classifyId);
                        if (!ListUtils.isEmpty(pushGroups)){
                            PushGroup pushGroup = pushGroups.get(0);
                            pushGroup.setBookGroupQrcodeId(groupQrcode.getId());
                            pushGroupDao.insert(pushGroup);
                        }
                    });
                    //String robotId = wechatGroupConsr.getRobotIdByGroupId(oneQrcode.getWeixinGroupId());
                    final String wechatGroupId = oneQrcode.getWeixinGroupId();
                    Map<String, BookWxQrcodeDTO> groupVersion = weixinQrcodeBiz.getGroupVersion(Collections.singletonList(wechatGroupId));
                    String ip = Optional.ofNullable(groupVersion.get(wechatGroupId)).orElse(new BookWxQrcodeDTO()).getWechatGroupIp();
                    SendWeixinRequestTools.changeGroupName(oneQrcode.getRobotWxId(), wechatGroupId, groupName, ip);
                }
                return oneQrcode.getQrcodeUrl();
            }
        }
        return StringUtil.EMPTY;
    }

    @ParamLog("将二维码改为已满群")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeToOverNumber(Long weixinQrcodeId, Long groupQrcodeId) {
        groupQrcodeDao.updateUseState(groupQrcodeId, QrcodeStatusEnum.OVER_NUMBER.value);
        weixinQrcodeBiz.updateUseState(weixinQrcodeId, QrcodeStatusEnum.OVER_NUMBER.value);
    }

    @ParamLog("将二维码改为未满群")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeToNotOverNumber(Long weixinQrcodeId, Long groupQrcodeId) {
        groupQrcodeDao.updateUseState(groupQrcodeId, QrcodeStatusEnum.ON_USE.value);
        weixinQrcodeBiz.updateUseState(weixinQrcodeId, QrcodeStatusEnum.ON_USE.value);
    }

    @Override
    public List<Long> listQrcodeIdsByLabelQuery(String query, Long proLabelId, Long depLabelId, Long purLabelId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("query", StringUtil.isEmpty(query) ? null : query);
        paramMap.put("proLabelId",proLabelId);
        paramMap.put("depLabelId",depLabelId);
        paramMap.put("purLabelId",purLabelId);
        List<Long> list = groupQrcodeDao.listQrcodeIdsByLabelQuery(paramMap);
        if (ListUtils.isEmpty(list)){
            list = new ArrayList<>();
        }
        return list;
    }

    @Override
    public List<Long> filterDeleteId(List<String> wxGroupIdList) {
        List<Long> qrcodeIds = groupQrcodeDao.filterDeleteQrcodeId(wxGroupIdList);
        if (ListUtils.isEmpty(qrcodeIds)){
            return new ArrayList<>();
        }else {
            return qrcodeIds;
        }
    }

    @Override
    public PageBeanNew<GroupQrcodeBookVO> listQrcodeByAdviser(Integer currentPage, Integer numPerPage, String name, Long adviserId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("adviserId", adviserId);
        paramMap.put("name", name);
        //获取二维码列表
        PageBeanNew<GroupQrcodeBookVO> pageBeanNew = groupQrcodeDao.listPageNew(new PageParam(currentPage,numPerPage), paramMap, "listQrcodeByAdviser");
        if (pageBeanNew == null || ListUtils.isEmpty(pageBeanNew.getRecordList())) {
            return new PageBeanNew<>(currentPage,numPerPage, new ArrayList<>());
        }
        return pageBeanNew;
    }

    @Override
    public PageBeanNew<GroupRiddleDTO> listPageRiddle(Long partyId, Integer currentPage, Integer numPerPage, String name) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("partyId", partyId);
        paramMap.put("name", name);
        PageBeanNew<GroupRiddleDTO> pageBeanNew = groupQrcodeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listPageRiddle");
        if (null == pageBeanNew || ListUtils.isEmpty(pageBeanNew.getRecordList())) {
            return new PageBeanNew<>(currentPage, numPerPage, 0, new ArrayList<>());
        }
        //标签
        Map<Long, String> labelMap = new HashMap<>();
        List<Long> labelIds = new ArrayList<>();
        List<Long> proLabels = pageBeanNew.getRecordList().stream().filter(s -> s.getProLabelId() != null).map(GroupRiddleDTO::getProLabelId).distinct().collect(Collectors.toList());
        List<Long> depLabels = pageBeanNew.getRecordList().stream().filter(s -> s.getDepLabelId() != null).map(GroupRiddleDTO::getDepLabelId).distinct().collect(Collectors.toList());
        List<Long> purLabels = pageBeanNew.getRecordList().stream().filter(s -> s.getPurLabelId() != null).map(GroupRiddleDTO::getPurLabelId).distinct().collect(Collectors.toList());
        if (!ListUtils.isEmpty(proLabels)) {
            labelIds.addAll(proLabels);
        }
        if (!ListUtils.isEmpty(depLabels)) {
            labelIds.addAll(depLabels);
        }
        if (!ListUtils.isEmpty(purLabels)) {
            labelIds.addAll(purLabels);
        }
        if (!ListUtils.isEmpty(labelIds)) {
            labelMap = labelConsr.getLabelName(labelIds);
        }
        if (!MapUtils.isEmpty(labelMap)) {
            for (GroupRiddleDTO riddleDTO : pageBeanNew.getRecordList()) {
                if (null != riddleDTO.getProLabelId() && labelMap.containsKey(riddleDTO.getProLabelId())) {
                    riddleDTO.setProLabelName(labelMap.get(riddleDTO.getProLabelId()));
                }
                if (null != riddleDTO.getDepLabelId() && labelMap.containsKey(riddleDTO.getDepLabelId())) {
                    riddleDTO.setDepLabelName(labelMap.get(riddleDTO.getDepLabelId()));
                }
                if (null != riddleDTO.getPurLabelId() && labelMap.containsKey(riddleDTO.getPurLabelId())) {
                    riddleDTO.setPurLabelName(labelMap.get(riddleDTO.getPurLabelId()));
                }
            }
        }
        return pageBeanNew;
    }

}
