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

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

import com.pcloud.book.advertising.biz.AdvertisingSpaceBiz;
import com.pcloud.book.advertising.biz.GroupTagBiz;
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.dao.GroupQrcodeDao;
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.GroupQrcodeServerDTO;
import com.pcloud.book.group.dto.PushAddUserMessageDTO;
import com.pcloud.book.group.dto.QrcodeNameAndProIdDTO;
import com.pcloud.book.group.dto.UpdateGroupNameDTO;
import com.pcloud.book.group.dto.WeixinQrcodeDTO;
import com.pcloud.book.group.entity.GroupQrcode;
import com.pcloud.book.group.enums.JoinGroupTypeEnum;
import com.pcloud.book.group.enums.QrcodeStatusEnum;
import com.pcloud.book.group.enums.UpdateStatusEnum;
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.biz.BookGuideBiz;
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.core.constant.MQTopicProducer;
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.amqp.core.AmqpTemplate;
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.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
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 BookGuideBiz bookGuideBiz;
    @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 GroupTagBiz groupTagBiz;
    @Autowired
    private AmqpTemplate amqpTemplate;


    @Override
    public Map<String, Integer> getGroupUserNum(List<String> wxGroups) {
        if (CollectionUtils.isEmpty(wxGroups)) {
            return Maps.newHashMap();
        }
        List<GroupQrcode> groupUserNum = groupQrcodeDao.getGroupUserNum(wxGroups);
        if (CollectionUtils.isEmpty(groupUserNum)) {
            return Maps.newHashMap();
        }
        return groupUserNum.stream().collect(Collectors.toMap(GroupQrcode::getWeixinGroupId, GroupQrcode::getUserNumber));
    }

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


    @Override
    public List<GroupQrcodeServerDTO> getWxGroupIdByServerId(List<Long> serverIds) {
        if (CollectionUtils.isEmpty(serverIds)) {
            return Lists.newArrayList();
        }
        return groupQrcodeDao.getWxGroupIdByServerId(serverIds);
    }

    /**
     * 处理群人数线程池
     */
//    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 = changeGroup(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 = changeGroup(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 = changeGroup(classifyId);
                log.info("[前端调用切群接口] getChangeGroupQrCode 群超出切群人数了，但是没有切群 重新分配群classifyId：{} url:{}", classifyId, url);
                return url;
            }
        }
        String url = null;
        List<ClassifyQrcodeVO> canUserQrcode = Lists.newArrayList();
        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()) {
                canUserQrcode.add(vo);
            }
        }
        // 获取群人数最少的可用群二维码返回出去
        if (!CollectionUtils.isEmpty(canUserQrcode)) {
            ClassifyQrcodeVO vo = canUserQrcode.stream().min(Comparator.comparingInt(ClassifyQrcodeVO::getUserNumber)).orElseGet(ClassifyQrcodeVO::new);
            url = StringUtil.isBlank(vo.getQrcodeUrl()) ? null : vo.getQrcodeUrl();
        }
        if (Objects.isNull(url)) {
            // 如果没有群则新增一个
            String qrcodeUrl = changeGroup(classifyId);
            log.info("[前端调用切群接口] getChangeGroupQrCode 没有可用群 重新分配群classifyId：{} url:{}", classifyId, url);
            return qrcodeUrl;
        }
        return url;
    }


    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, 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, Long proLabelId, Long depLabelId, 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);
        map.put("proLabelId", proLabelId);
        map.put("depLabelId", depLabelId);
        final PageBeanNew<ListGroupQrcodeResponseVO> groupQrcode = this.groupQrcodeDao.listPageNew(pageParam, map, "listAllGroupQrcode");
        if (null == groupQrcode || CollectionUtils.isEmpty(groupQrcode.getRecordList())) {
            return groupQrcode;
        }
        final List<Long> adviserIds = Lists.newArrayList();
        final List<Long> depLabelIds = Lists.newArrayList();
        final List<Long> proLabelIds = Lists.newArrayList();
        for (ListGroupQrcodeResponseVO vo : groupQrcode.getRecordList()) {
            adviserIds.add(vo.getAdviserId());
            depLabelIds.add(vo.getDepLabelId());
            proLabelIds.add(vo.getProLabelId());
        }
        Map<Long, String> labelName = labelConsr.getLabelName(depLabelIds);
        final Map<Long, String> names = adviserConsr.getNames(adviserIds);
        for (ListGroupQrcodeResponseVO vo : groupQrcode.getRecordList()) {
            vo.setAdviserName(names.get(vo.getAdviserId()));
            vo.setDepLabelName(labelName.get(vo.getDepLabelId()));
            vo.setProLabelName(labelName.get(vo.getProLabelId()));
        }
        return groupQrcode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ParamLog("新增群二维码")
    public Long insert(GroupQrcode groupQrcode) {
        groupQrcodeDao.insert(groupQrcode);
        //判断广告位标记
        groupTagBiz.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, "微信群名称不能为空");
        }
        if (wechatGroupName.contains("#")) {
            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);
        }
        UpdateGroupNameDTO updateGroupNameDTO = new UpdateGroupNameDTO();
        updateGroupNameDTO.setId(id);
        updateGroupNameDTO.setGroupName(wechatGroupName);
        amqpTemplate.convertAndSend(MQTopicProducer.EXCHAGE, MQTopicProducer.MODIFY_WXGROUP_NAME, updateGroupNameDTO);
    }

    @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);
        }
        //获取群基本信息
        GroupQrcodeDTO groupQrcodeDTO = groupQrcodeDao.getGroupQrcodeInfo(weixinGroupId);
        log.info("[新增一个用户] groupQrcodeDTO:{}", groupQrcodeDTO);
        if (groupQrcodeDTO == null) {
            return;
        }
        // 新用户进群时系统消息群人数不准，所以从系统中取然后+1，更新群人数操作会在群消息地方处理
        memberCount = groupQrcodeDTO.getUserNumber() + 1;
        // 当群人数超过限制，或者群二维码更新状态为失败时更新群状态为满群
        boolean overstaff = memberCount >= ((JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(groupQrcodeDTO.getJoinGroupType()) ? 100 : 500)) && QrcodeStatusEnum.ON_USE.value.equals(groupQrcodeDTO.getUseState());
        Integer updatState = Optional.ofNullable(weixinQrcodeBiz.getGroupVersion(Collections.singletonList(weixinGroupId))).map(x -> x.get(weixinGroupId)).map(BookWxQrcodeDTO::getUpdateState).orElse(-1);
        if (overstaff || UpdateStatusEnum.FIAL.value.equals(updatState)) {
            //将二维码修改为已满群状态
            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;
        }
        PushAddUserMessageDTO pushAddUserMessageDTO = new PushAddUserMessageDTO();
        pushAddUserMessageDTO.setWeixinGroupId(weixinGroupId);
        pushAddUserMessageDTO.setTime(System.currentTimeMillis());
        pushAddUserMessageDTO.setNickName(nickName);
        pushAddUserMessageDTO.setMemberCount(memberCount);
        pushAddUserMessageDTO.setRobotId(robotIdByGroupId);
        pushAddUserMessageDTO.setIp(ip);
        bookGuideBiz.sendGuideMessage(pushAddUserMessageDTO);
    }


    @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, String altId) {
        Integer joinGroupType = null;
        ClassifyVO classifyVOOne = bookGroupClassifyBiz.getClassify(classifyId);
        if (classifyVOOne != null && classifyVOOne.getBookGroupId() != null) {
            QrcodeNameAndProIdDTO qrcodeNameAndProId = bookGroupBiz.getQrcodeNameAndProId(classifyVOOne.getBookGroupId());
            if (qrcodeNameAndProId!=null){
                joinGroupType = qrcodeNameAndProId.getJoinGroupType();
            }
        }
        WeixinQrcodeDTO oneQrcode = weixinQrcodeBiz.getOneQrcode(joinGroupType, altId);
        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){
                dealAfterChangeANewGroup(oneQrcode, classifyId);
                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;
    }

    @Override
    public GroupQrcodeInfo4Advertising getWechatGroupInfo(Long qrcodeId) {
        GroupQrcode groupQrcode = groupQrcodeDao.getGroupQrcodeByqrcodeId(qrcodeId);
        GroupQrcodeInfo4Advertising groupQrcodeInfo4Advertising = new GroupQrcodeInfo4Advertising();
        groupQrcodeInfo4Advertising.setAdviserId(groupQrcode.getCreateUser());
        groupQrcodeInfo4Advertising.setGroupName(groupQrcode.getGroupName());
        groupQrcodeInfo4Advertising.setQrcodeUrl(groupQrcode.getQrcodeUrl());
        return groupQrcodeInfo4Advertising;
    }

    @Override
    public Map<Long, GroupQrcodeInfo4Advertising> getWechatGroupInfoMap(List<Long> qrcodeIds) {
        if (ListUtils.isEmpty(qrcodeIds)){
            return new HashMap<>();
        }
        return groupQrcodeDao.getWechatGroupInfoMap(qrcodeIds);
    }

    @Override
    public PageBeanNew<GroupQrcodeBookVO> listQrcodeByPcloud(Integer currentPage, Integer numPerPage, String name, Long depLabelId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("name", name);
        paramMap.put("depLabelId", depLabelId);
        PageBeanNew<GroupQrcodeBookVO> pageBeanNew = groupQrcodeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listQrcodeByPcloud");
        if (pageBeanNew == null || ListUtils.isEmpty(pageBeanNew.getRecordList())) {
            return new PageBeanNew<>(currentPage, numPerPage, 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(GroupQrcodeBookVO::getProLabelId).distinct().collect(Collectors.toList());
        List<Long> depLabels = pageBeanNew.getRecordList().stream().filter(s -> s.getDepLabelId() != null).map(GroupQrcodeBookVO::getDepLabelId).distinct().collect(Collectors.toList());
        List<Long> purLabels = pageBeanNew.getRecordList().stream().filter(s -> s.getPurLabelId() != null).map(GroupQrcodeBookVO::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 (GroupQrcodeBookVO qrcodeBookVO : pageBeanNew.getRecordList()) {
                if (null != qrcodeBookVO.getProLabelId() && labelMap.containsKey(qrcodeBookVO.getProLabelId())) {
                    qrcodeBookVO.setProLabelName(labelMap.get(qrcodeBookVO.getProLabelId()));
                }
                if (null != qrcodeBookVO.getDepLabelId() && labelMap.containsKey(qrcodeBookVO.getDepLabelId())) {
                    qrcodeBookVO.setDepLabelName(labelMap.get(qrcodeBookVO.getDepLabelId()));
                }
                if (null != qrcodeBookVO.getPurLabelId() && labelMap.containsKey(qrcodeBookVO.getPurLabelId())) {
                    qrcodeBookVO.setPurLabelName(labelMap.get(qrcodeBookVO.getPurLabelId()));
                }
            }
        }
        return pageBeanNew;
    }

    @ParamLog("切群之后要做的事")
    @Override
    public void dealAfterChangeANewGroup(WeixinQrcodeDTO oneQrcode, Long classifyId){
        //获取标签对应基本信息
        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);
                }
            });
            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);
        }
    }

    @ParamLog("根据类型获取当前群总人数")
    @Override
    public Integer getUserCountByJoinGroupType(Integer joinGroupType) {
        return groupQrcodeDao.getUserCountByJoinGroupType(joinGroupType);
    }

}
