package com.gic.haoban.manage.service.service.out.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.JSONResponse;
import com.gic.api.base.dto.SubscribeMessageDTO;
import com.gic.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.EntityUtil;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.app.customer.dto.ChildDTO;
import com.gic.haoban.app.customer.dto.CustomerDTO;
import com.gic.haoban.app.customer.dto.FilterListDTO;
import com.gic.haoban.app.customer.dto.MemberInfoListParamsDTO;
import com.gic.haoban.app.customer.enums.GicQywxSyncTypeEnum;
import com.gic.haoban.app.customer.enums.QywxSyncTaskTypeEnum;
import com.gic.haoban.app.customer.service.api.service.CustomerApiService;
import com.gic.haoban.base.api.common.ServiceResponse;
import com.gic.haoban.common.utils.DingUtils;
import com.gic.haoban.manage.api.constants.Manage3Constants;
import com.gic.haoban.manage.api.dto.ClerkMainStoreRelatedDTO;
import com.gic.haoban.manage.api.dto.ContentMaterialDTO;
import com.gic.haoban.manage.api.dto.ExternalClerkRelatedDTO;
import com.gic.haoban.manage.api.dto.ExternalMemberLogDTO;
import com.gic.haoban.manage.api.dto.ExternalUserDTO;
import com.gic.haoban.manage.api.dto.FriendStoreInfoDTO;
import com.gic.haoban.manage.api.dto.MemberStoreDTO;
import com.gic.haoban.manage.api.dto.MemberUnionidRelatedDTO;
import com.gic.haoban.manage.api.dto.MemberUnionidWechatAccountQDTO;
import com.gic.haoban.manage.api.dto.QwFrientNoticeDTO;
import com.gic.haoban.manage.api.dto.SecretSettingDTO;
import com.gic.haoban.manage.api.dto.StaffClerkRelationDTO;
import com.gic.haoban.manage.api.dto.WxEnterpriseQwDTO;
import com.gic.haoban.manage.api.dto.hm.HmQrcodeDTO;
import com.gic.haoban.manage.api.dto.qdto.hm.WxUserAddLogQDTO;
import com.gic.haoban.manage.api.enums.SecretTypeEnum;
import com.gic.haoban.manage.api.service.CheckQywxSettingApiService;
import com.gic.haoban.manage.api.service.ClerkMainStoreRelatedApiService;
import com.gic.haoban.manage.api.service.ExternalClerkRelatedApiService;
import com.gic.haoban.manage.api.service.MemberUnionidRelatedApiService;
import com.gic.haoban.manage.api.service.hm.HmQrcodeApiService;
import com.gic.haoban.manage.service.config.Config;
import com.gic.haoban.manage.service.dao.mapper.StaffMapper;
import com.gic.haoban.manage.service.dao.mapper.TabHaobanExternalClerkRelatedMapper;
import com.gic.haoban.manage.service.entity.TabExternalMemberLog;
import com.gic.haoban.manage.service.entity.TabHaobanClerkMainStoreRelated;
import com.gic.haoban.manage.service.entity.TabHaobanExternalClerkRelated;
import com.gic.haoban.manage.service.entity.TabHaobanStaff;
import com.gic.haoban.manage.service.entity.TabHaobanWxEnterprise;
import com.gic.haoban.manage.service.entity.TabHaobanWxEnterpriseRelated;
import com.gic.haoban.manage.service.exception.WxApiLimitException;
import com.gic.haoban.manage.service.pojo.DealQywxExternalUserPojo;
import com.gic.haoban.manage.service.pojo.ExternalUserPojo;
import com.gic.haoban.manage.service.pojo.QywxTagSyncInfoPojo;
import com.gic.haoban.manage.service.pojo.bo.hm.HmLinkBO;
import com.gic.haoban.manage.service.pojo.bo.hm.KeyDataLinkBO;
import com.gic.haoban.manage.service.service.ClerkMainStoreRelatedService;
import com.gic.haoban.manage.service.service.ExternalClerkRelatedService;
import com.gic.haoban.manage.service.service.ExternalMemberService;
import com.gic.haoban.manage.service.service.KeyDataService;
import com.gic.haoban.manage.service.service.MemberUnionRelatedService;
import com.gic.haoban.manage.service.service.QywxSendService;
import com.gic.haoban.manage.service.service.SecretSettingService;
import com.gic.haoban.manage.service.service.StaffClerkRelationService;
import com.gic.haoban.manage.service.service.StaffService;
import com.gic.haoban.manage.service.service.WelcomeSendService;
import com.gic.haoban.manage.service.service.WxEnterpriseRelatedService;
import com.gic.haoban.manage.service.service.WxEnterpriseService;
import com.gic.haoban.manage.service.service.chat.GroupChatService;
import com.gic.haoban.manage.service.service.hm.HmLinkService;
import com.gic.haoban.manage.service.service.hm.WxUserAddLogService;
import com.gic.haoban.manage.service.util.EmojiFilterUtil;
import com.gic.member.api.dto.MemberDTO;
import com.gic.member.api.dto.MemberSimpleDetailDTO;
import com.gic.member.api.dto.MemberSourceDetailDTO;
import com.gic.member.api.dto.MemberSourceShowDTO;
import com.gic.member.api.dto.QywxMemberQDTO;
import com.gic.member.api.service.MemberApiService;
import com.gic.member.api.service.MemberEntranceApiService;
import com.gic.member.api.service.MemberService;
import com.gic.member.api.service.MemberStoreService;
import com.gic.member.tag.api.dto.outapi.MemberTagSingleDTO;
import com.gic.member.tag.api.service.MemberTagOpenApiService;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;
import com.gic.wechat.api.dto.qywx.UnionidToExternalUseridDTO;
import com.gic.wechat.api.service.qywx.QywxSuiteApiService;
import com.gic.wechat.api.service.qywx.QywxUserApiService;
import com.google.common.collect.Sets;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.crypto.SecureUtil;
@Service
public class MemberUnionidRelatedApiServiceImpl implements MemberUnionidRelatedApiService {

    private static final Logger log = LogManager.getLogger(MemberUnionidRelatedApiServiceImpl.class);
    private static final String SELF_APP = "selfSuiteId";
    /**
     * 限制次数
     */
    private static final Integer MAX_TIMES = 5;

    @Autowired
    private MemberUnionRelatedService memberUnionRelatedService;
    @Autowired
    private StaffService staffService;
    @Autowired
    private QywxUserApiService qywxUserApiService;
    @Autowired
    private WxEnterpriseRelatedService wxEnterpriseRelatedService;
    @Autowired
    private WxEnterpriseService wxEnterpriseService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private ClerkMainStoreRelatedService clerkMainStoreRelatedService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private Config config;
    @Autowired
    private QywxSuiteApiService qywxSuiteApiService;
    @Autowired
    private SecretSettingService secretSettingService;
    @Autowired
    private StaffClerkRelationService staffClerkRelationService;
    @Autowired
    private ExternalClerkRelatedService externalClerkRelatedService;
    @Autowired
    private CheckQywxSettingApiService checkQywxSettingApiService;
    @Autowired
    private CustomerApiService customerApiService;
    @Autowired
    private MemberApiService memberApiService;
    @Autowired
    private TabHaobanExternalClerkRelatedMapper externalClerkRelatedMapper;
    @Autowired
    private ExternalClerkRelatedApiService externalClerkRelatedApiService;
    @Autowired
    private MemberStoreService memberStoreService;
    @Autowired
    private HmQrcodeApiService hmQrcodeApiService;
    @Autowired
    private WxUserAddLogService wxUserAddLogService;
    @Autowired
    private KeyDataService keyDataService;
    @Autowired
    private MemberTagOpenApiService memberTagOpenApiService;
    @Autowired
    private HmLinkService hmLinkService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private StaffMapper staffMapper;
    @Autowired
    private MemberEntranceApiService memberEntranceApiService;
    @Autowired
    private QywxSendService qywxSendService ;
    @Autowired
    private GroupChatService groupChatService ;
    @Autowired
    private WelcomeSendService welcomeSendService ;
    @Autowired
    private ExternalMemberService externalMemberService ;
    @Autowired
    private ClerkMainStoreRelatedApiService  clerkMainStoreRelatedApiService ;
    
    GicMQClient instance = GICMQClientUtil.getClientInstance();

    @Override
    public void dealQywxExternalUser(String params) {
        DealQywxExternalUserPojo externalUserPojo = JSONObject.parseObject(params, DealQywxExternalUserPojo.class);
        QwFrientNoticeDTO qwFrientNoticeDTO = externalUserPojo.getData();
        int type = externalUserPojo.getType();
        String wxUserId = qwFrientNoticeDTO.getWxUserId();
        MemberUnionidRelatedDTO memberUnionidRelatedDTO = EntityUtil.changeEntityByJSON(MemberUnionidRelatedDTO.class, qwFrientNoticeDTO);
        if (type == DealQywxExternalUserPojo.DealType.add.getType()) {
            log.info("新增外部联系人回调开始：{}", params);
            this.addMemberUnionidRelatedNew(memberUnionidRelatedDTO, wxUserId);
        } else if (type == DealQywxExternalUserPojo.DealType.edit.getType()) {
            log.info("编辑外部联系人回调开始：{}", params);
            this.editMemberUnionidRelatedProcess(memberUnionidRelatedDTO, wxUserId);
        } else if (type == DealQywxExternalUserPojo.DealType.del.getType()) {
            log.info("删除外部联系人回调开始：{}", params);
            String changeType = qwFrientNoticeDTO.getChangeType();
            //欧泊莱定制
            if ("del_follow_user".equals(changeType)) {
                delExternalByUser(wxUserId, memberUnionidRelatedDTO);
                return;
            }
            log.info("导购删除好友");
            this.delMemberUnionidRelatedProcess(memberUnionidRelatedDTO, wxUserId);
        }
    }

    /**
     * 会员删除导购
     * @param wxUserId
     * @param memberUnionidRelatedDTO
     */
    private void delExternalByUser(String wxUserId, MemberUnionidRelatedDTO memberUnionidRelatedDTO) {
        log.info("会员删除导购");
        String corpId = memberUnionidRelatedDTO.getCorpid();
        TabHaobanWxEnterprise wxEnterprise = this.wxEnterpriseService.getEnterpriseBycorpId(corpId);
        if (wxEnterprise == null) {
            log.info("查询TabHaobanWxEnterprise为空：{}", corpId);
            return;
        }
        String wxEnterpriseId = wxEnterprise.getWxEnterpriseId();
        memberUnionidRelatedDTO.setWxEnterpriseId(wxEnterpriseId);
        TabHaobanStaff staff = this.staffMapper.selectByUserIdAndEnterpriseId(wxUserId, wxEnterpriseId);
        if (staff == null) {
            log.error("员工不存在：{}", wxUserId);
            return;
        }
        String staffId = staff.getStaffId();
        memberUnionidRelatedDTO.setStaffId(staffId);
        List<TabHaobanExternalClerkRelated> tabHaobanExternalClerkRelatedList = externalClerkRelatedService.listByExternalUseridAndWxUserId(memberUnionidRelatedDTO.getExternalUserid(), memberUnionidRelatedDTO.getStaffId());
        if (CollectionUtils.isEmpty(tabHaobanExternalClerkRelatedList)) {
            log.error("无好友记录");
            return;
        }
        TabHaobanExternalClerkRelated related = tabHaobanExternalClerkRelatedList.get(0);
        String enterpriseId = related.getEnterpriseId();
        //添加日志
        WxUserAddLogQDTO wxUserAddLogQDTO = new WxUserAddLogQDTO();
        wxUserAddLogQDTO.setWxEnterpriseId(wxEnterpriseId);
        wxUserAddLogQDTO.setEnterpriseId(enterpriseId);
        wxUserAddLogQDTO.setMemberId(related.getMemberId());
        wxUserAddLogQDTO.setUnionid(related.getUnionid());
        wxUserAddLogQDTO.setDelFlag(true);
        wxUserAddLogQDTO.setExternalUserid(related.getExternalUserId());
        wxUserAddLogQDTO.setStaffId(related.getStaffId());
        wxUserAddLogQDTO.setClerkId(related.getClerkId());
        wxUserAddLogQDTO.setDelClerkFlag(true);
        wxUserAddLogService.save(wxUserAddLogQDTO);

        addDelFriendEvent(related.getUnionid(), related.getClerkId(), wxEnterpriseId, enterpriseId, related.getMemberId(), related.getStoreId(), 0);
    }

    @Override
    public List<MemberStoreDTO> listByExTernalUseridAndWxUserId(String externalUserid, String staffId, String storeId) {
        List<TabHaobanExternalClerkRelated> list = externalClerkRelatedService.listByExternalUseridAndWxUserId(externalUserid, staffId);
        List<MemberStoreDTO> result = new ArrayList<>();
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        TabHaobanStaff haobanStaff = staffService.selectById(staffId);
        if (null == haobanStaff) {
            log.info("staff不存在");
            return null;
        }
        List<StaffClerkRelationDTO> clerkRelationDTOS = staffClerkRelationService.listBindCodeByStaffId(null, haobanStaff.getStaffId());
        if (CollectionUtil.isEmpty(clerkRelationDTOS)) {
            log.info("staff关联门店不存在1");
            return null;
        }
        List<String> storeIds = clerkRelationDTOS.stream().filter(s -> (s.getStoreId() != null || "".equals(s.getStoreId()))).map(s -> s.getStoreId()).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(storeIds)) {
            log.info("staff关联门店不存在2");
            return null;
        }
        log.info("门店信息storeIds={}", JSON.toJSONString(storeIds));
        //2、获取member的storeId
        for (TabHaobanExternalClerkRelated tab : list) {
            if (StringUtils.isNotBlank(storeId) && (!storeId.equals(tab.getStoreId()))) {
                log.info("门店不符合,跳过");
                continue;
            }
            String memberId = tab.getMemberId();
            if (StringUtils.isEmpty(memberId)) {
                log.info("memberId null 跳过");
                continue;
            }
            CustomerDTO params = new CustomerDTO();
            params.setClerkType("0");
            params.setStoreId(tab.getStoreId());
            params.setClerkId(tab.getClerkId());
            params.setEnterpriseId(tab.getEnterpriseId());
            params.setStoreManagerFlag(isManager(tab.getClerkId()));

            MemberInfoListParamsDTO memberInfoListParamsDTO = new MemberInfoListParamsDTO();
            memberInfoListParamsDTO.setMemberId(memberId);

            FilterListDTO filterListDTO = new FilterListDTO();
            filterListDTO.setFilterType("4");
            ChildDTO childDTO = new ChildDTO();
            childDTO.setId("");
            filterListDTO.setChild(childDTO);
            List<FilterListDTO> filterList = new ArrayList<>();
            filterList.add(filterListDTO);

            memberInfoListParamsDTO.setFilterList(filterList);

            boolean flag = customerApiService.checkMemberRangeByMemberId(params, memberInfoListParamsDTO);
            MemberStoreDTO dto = new MemberStoreDTO();
            dto.setMemberId(tab.getMemberId());
            dto.setStoreId(tab.getStoreId());
            if (flag) {
                dto.setHasRight(1);
            } else {
                dto.setHasRight(0);
            }
            result.add(dto);
        }
        return result;
    }

    private boolean isManager(String clerkId) {
        ClerkDTO clerkDTO = clerkService.getclerkById(clerkId);
        if (clerkDTO != null) {
            Integer isManager = clerkDTO.getClerkType();
            return isManager != null && isManager == 1 && clerkDTO.getStatus() == 1;
        }
        return false;
    }

    /**
     * 根据导购导购微信id和会员id查询关联关系
     *
     * @return : 返回关联关系
     */
    @Override
    public ExternalClerkRelatedDTO getByWxUserIdMemberId(String staffId, String memberId) {
        return externalClerkRelatedService.getByMemberId(staffId, memberId);
    }

    @Override
    public String addMemberUnionidRelated(QwFrientNoticeDTO dto) {
        DealQywxExternalUserPojo dealQywxExternalUserPojo = new DealQywxExternalUserPojo();
        dealQywxExternalUserPojo.setType(DealQywxExternalUserPojo.DealType.add.getType());
        dealQywxExternalUserPojo.setData(dto);
        this.sendWelcome(dto);
        String mqName = "dealQywxExternalUserMq" ;
        if(this.mqCheck(dto)) {
            mqName = "dealQywxExternalUserMq2";
        }
        try {
            instance.sendMessage(mqName, JSONObject.toJSONString(dealQywxExternalUserPojo));
        } catch (Exception e) {
            log.info("异步处理异常：{}", e);
        }
        return null;
    }
    
    
    private void sendWelcome(QwFrientNoticeDTO dto) {
        String suiteid = dto.getSuiteid();
        if (SELF_APP.equals(suiteid)) {
           return ;
        } 
        if(StringUtils.isEmpty(dto.getWelcomeCode())) {
            return ;
        }
        try {
            instance.sendMessage("qywxWelcomeSendMQ", JSONObject.toJSONString(dto));
        } catch (Exception e) {
            log.info("异步处理异常：{}", e);
        }
    }
    // 加好友量大的迁移到mq2
    private boolean mqCheck(QwFrientNoticeDTO dto) {
        int maxCount = 800 ;
        boolean flag = false ;
        Object obj = RedisUtil.getCache("dealQywxExternalUserMq2") ;
        String corpid = dto.getCorpid() ;
        if(null != obj) {
            String str = obj.toString() ;
            if(StringUtils.isNotBlank(corpid) && str.contains(corpid)) {
                flag = true ;
                log.info("加好友计数,手动配置到userMq2,corpid={}",corpid);
                return flag ;
            }
        }
        if(null != obj && obj.toString().equals("0")) {
            return false ;
        }
        TabHaobanWxEnterprise wxEnterprise = this.wxEnterpriseService.getEnterpriseBycorpId(corpid) ;
        if(null != wxEnterprise) {
            String wxEnterpriseId = wxEnterprise.getWxEnterpriseId() ;
            flag = this.needToMq2(wxEnterpriseId) ;
            if(!flag) {
                long times = this.getTimes(wxEnterpriseId) ;
                if("wp59NLDQAAtTbif_SxAixUQVqMld4vug".equals(corpid)) {
                    maxCount = 2 ;
                }
                log.info("dealQywxExternalUserMq2={},{},{}",times,maxCount,wxEnterpriseId);
                if(times>maxCount) {
                    if(!needToMq2(wxEnterpriseId)) {
                        log.info("加好友计数发送告警,id={}",wxEnterpriseId);
                        DingUtils.send("加好友mq切换,企业="+ wxEnterpriseId, false);
                    }
                    log.info("加好友计数,自动到userMq2,{}",wxEnterpriseId);
                    this.addToMq2Mark(wxEnterpriseId);
                    flag = true ;
                }
            }
        }
        return flag ;
    }
    
    private long getTimes(String wxEnterpriseId) {
        String key = "qwadd:count:"+wxEnterpriseId ;
        RAtomicLong cache = RedisUtil.getRedisClient().getAtomicLong(key);
        long val = cache.addAndGet(1);
        if (val <= 1) {
            cache.expire(1, TimeUnit.MINUTES);
        }
        return val ;
    }
    
    private void addToMq2Mark(String wxEnterpriseId) {
        String key = "qwadd:count2:"+wxEnterpriseId ;
        RedisUtil.setCache(key, 1,600L);
    }
    
    private boolean needToMq2(String wxEnterpriseId) {
        String key = "qwadd:count2:"+wxEnterpriseId ;
        return null != RedisUtil.getCache(key) ;
    }
    
    @Override
    public String addMemberUnionidRelatedNew(MemberUnionidRelatedDTO dto, String wxUserId) {
        String corpId = dto.getCorpid();
        TabHaobanWxEnterprise wxEnterprise = this.wxEnterpriseService.getEnterpriseBycorpId(corpId) ;
        if (wxEnterprise == null) {
            log.info("企业不存在,corpid={}", corpId);
            return null;
        }
        String wxEnterpriseId = wxEnterprise.getWxEnterpriseId() ;
        TabHaobanStaff staff = this.staffMapper.selectByUserIdAndEnterpriseId(wxUserId, wxEnterpriseId) ;
        if(null == staff) {
            log.info("staff不存在,wxEnterpriseId={},wxUserid={}", wxEnterpriseId , wxUserId);
            return null ;
        }
        dto.setWxEnterpriseId(wxEnterpriseId);
        dto.setStaffId(staff.getStaffId());
        // 新增unionid表
        dto = getMemberUnionidRelatedDTONew(dto, wxUserId);
        if (null == dto) {
            log.info("代开发和第三方未全部收到/未获取到客户详情");
            return null;
        }
        this.insertExternalClerkRelatedNew(dto, wxUserId,staff.getStaffName());
        return dto.getMemberUnionidRelatedId();
    }

    private void insertExternalClerkRelatedNew(MemberUnionidRelatedDTO dto, String wxUserId , String staffName) {
        log.info("新增外部联系人,处理好友表={},wxUserId={}", JSON.toJSONString(dto),wxUserId);
        String wxEnterpriseId = dto.getWxEnterpriseId();
        String name = dto.getExternalName();
        String createTime = dto.getAddCreateTime();
        String externalUserId = dto.getExternalUserid();
        if (StringUtils.isAnyBlank(wxUserId, wxEnterpriseId, name, createTime, externalUserId)) {
            log.error("新增外部联系人,缺少必须字段：wxUserId:{},wxEnterpriseId:{},name:{},createTime:{},externalUserId:{}", wxUserId, wxEnterpriseId, name, createTime, externalUserId);
            return;
        }
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            log.info("企业不存在,wxEnterpriseId={}", wxEnterpriseId);
            return;
        }
        String unionid = dto.getUnionid();
        String state = dto.getState();
        String staffId = dto.getStaffId();
        boolean isHmUnionid = false;
        String mobile = "";
        String memberLabelId = "";
        Long hmId = null;
        Long linkId = null ;
        String hyClerkId = null ;
        StaffClerkRelationDTO staffClerkRelationDTO = null;
        boolean mainStoreCheck = true ;
        //活码处理 "DT" "HM"
        if (StringUtils.isNotBlank(state) && (state.startsWith(Manage3Constants.HM) || state.startsWith(Manage3Constants.DT))) {
            mainStoreCheck = false ;
            String id = state.substring(2);
            if(state.startsWith(Manage3Constants.HM)) {
                hmId = Convert.toLong(id);
            }else if(state.startsWith(Manage3Constants.DT)) {
                KeyDataLinkBO linkData = keyDataService.getDataForHmLink(id);
                if(null == linkData) {
                    log.error("活码keyDate查询不到,id={}", id);
                    return ;
                }
                linkId = linkData.getLinkId();
                hmId = linkData.getHmId();
                mobile = linkData.getMobile();
                if(StringUtils.isNotBlank(linkData.getUnionid())) {
                    unionid = linkData.getUnionid();
                    isHmUnionid = true;
                }
            }
            log.info("活码{},hmId={},linkId={},isHmUnionid={},unionid={},mobile={}", state,hmId, linkId, isHmUnionid,unionid,mobile);
            HmQrcodeDTO hmDTO = hmQrcodeApiService.getSimpleById(hmId);
            if (hmDTO == null) {
                log.error("活码查询不到,hmId:{}", hmId);
                return;
            }
            memberLabelId = this.getMemberLabel(state, hmDTO.getMemberLabelId(), wxEnterpriseId, linkId) ;
            hyClerkId = this.welcomeSendService.getHmClerk(hmDTO,wxEnterpriseId,staffId) ;
            if(StringUtils.isBlank(hyClerkId)) {
                log.info("【新增外部联系人】hm未获取到导购,staffId={}",staffId);
                return ;
            }
            staffClerkRelationDTO = staffClerkRelationService.getBindByClerkId(hyClerkId, wxEnterpriseId);
        }
        if(mainStoreCheck) {
            TabHaobanClerkMainStoreRelated mainStoreRelated = clerkMainStoreRelatedService.getMainStoreByStaffId(staffId, wxEnterpriseId);
            if (mainStoreRelated == null) {
                log.info("【新增外部联系人】主门店为空:staffId={}", staffId);
                // this.sendWelcome(dto, qwDTO, null, staffId, null , null);
                return;
            }
            staffClerkRelationDTO = staffClerkRelationService.getOneBindByStoreId(staffId, mainStoreRelated.getStoreId());
        }
        
        if (staffClerkRelationDTO == null) {
            log.info("【新增外部联系人】staff无关联导购,staffId={}",staffId);
            return;
        }
        String enterpriseId = staffClerkRelationDTO.getEnterpriseId();
        hyClerkId = staffClerkRelationDTO.getClerkId() ;
        log.info("新增外部联系人,enterpriseId={},clerk={}",enterpriseId,hyClerkId);
        TabHaobanWxEnterpriseRelated wxEnterpriseRelated = wxEnterpriseRelatedService.getByEnterpriseId(wxEnterpriseId, enterpriseId);
        if (wxEnterpriseRelated == null) {
            log.info("加好友失败,商户未关联好办企业,wxEnterpriseId={},enterpriseId={}", wxEnterpriseId, enterpriseId);
            return;
        }
        String memberId = null;
        boolean addByWelcome = this.wxEnterpriseRelatedService.getAddByWelcomeFlag(wxEnterpriseRelated,unionid,isHmUnionid) ;
        log.info("新增外部联系人,是否通过欢迎语={},wxEnterpriseId:{},enterpriseId={},unionid={}",addByWelcome,wxEnterpriseId,enterpriseId,unionid);
        if(addByWelcome) {
            unionid = null ;
            dto.setUnionid(unionid);
            // 查询
            String relationKey = SecureUtil.md5(staffId + dto.getExternalUserid());
            TabExternalMemberLog externalMemberLog = this.externalMemberService.selectRelationKey(enterpriseId, relationKey) ;
            if(null != externalMemberLog && StringUtils.isNotEmpty(externalMemberLog.getUnionid())) {
                log.info("通过欢迎语,但查询到unionid,relationkey={}",relationKey) ;
                unionid = externalMemberLog.getUnionid() ;
                dto.setUnionid(unionid);
                memberId = addExternalClerkRelated(dto, staffId, staffClerkRelationDTO, wxEnterpriseRelated, mobile,qwDTO);
                this.externalMemberService.updateStatus(enterpriseId, externalMemberLog.getLogId(), 2) ;
            }else {
                this.addFriendByWelcome(dto, staffClerkRelationDTO,qwDTO);
            }
        }else {
            dto.setUnionid(unionid);
            memberId = addExternalClerkRelated(dto, staffId, staffClerkRelationDTO, wxEnterpriseRelated, mobile,qwDTO);
        }
        // 更新后面加好友数
        if(null != hmId) {
            this.hmQrcodeApiService.updateAddNumById(hmId, hyClerkId);
        }
       //设置会员标签
       this.setMemberTag(enterpriseId, memberLabelId, memberId);
       //加好友增加数量
       this.staffService.updateAddNumById(staffId);
       WxUserAddLogQDTO wxUserAddLogQDTO = new WxUserAddLogQDTO();
       wxUserAddLogQDTO.setLinkId(linkId);
       wxUserAddLogQDTO.setHmId(hmId);
       wxUserAddLogQDTO.setWxEnterpriseId(wxEnterpriseId);
       wxUserAddLogQDTO.setEnterpriseId(enterpriseId);
       wxUserAddLogQDTO.setMemberId(memberId);
       wxUserAddLogQDTO.setUnionid(unionid);
       wxUserAddLogQDTO.setDelFlag(false);
       wxUserAddLogQDTO.setExternalUserid(externalUserId);
       wxUserAddLogQDTO.setStaffId(staffId);
       wxUserAddLogQDTO.setStaffName(staffName);
       wxUserAddLogQDTO.setClerkId(hyClerkId);
       this.wxUserAddLogService.save(wxUserAddLogQDTO);
       if(StringUtils.isNotBlank(memberId)) {
           this.groupChatService.matchGicMember(wxEnterpriseId, enterpriseId, memberId, externalUserId);
       }
    }
    
    // 获取hm配置的会员标签
    private String getMemberLabel(String state , String hmMemberLableId , String wxEnterpriseId, Long linkId) {
        if(state.startsWith(Manage3Constants.HM)) {
            return hmMemberLableId ;
        }
        if(null != linkId) {
            HmLinkBO link = hmLinkService.getByLinkId(wxEnterpriseId, null, linkId);
            if (link != null) {
                return link.getMemberLabelId();
            }
        }
        return null ;
    }
    
    /**
     * 设置活码标签
     */
    private void setMemberTag(String enterpriseId, String memberLabelId, String memberId) {
        log.info("会员打标签,memberLabelId:{},memberId:{},enterpriseId={}", memberLabelId, memberId,enterpriseId);
        if (StringUtils.isNoneBlank(enterpriseId,memberLabelId,memberId)) {
            MemberTagSingleDTO tagSingleDTO = new MemberTagSingleDTO();
            tagSingleDTO.setEnterpriseId(enterpriseId);
            tagSingleDTO.setOptType(0);
            tagSingleDTO.setMemberId(memberId);
            tagSingleDTO.setTagItemIdList(Collections.singletonList(memberLabelId));
            this.memberTagOpenApiService.saveMemberTagSingle(tagSingleDTO);
        }
    }

    /**
     *  不是通过欢迎语的添加好友
     */
    private String addExternalClerkRelated(MemberUnionidRelatedDTO dto, String staffId, StaffClerkRelationDTO staffClerkRelationDTO,
                                           TabHaobanWxEnterpriseRelated wxEnterpriseRelated, String mobile,WxEnterpriseQwDTO qwDTO) {
        String wxEnterpriseId = dto.getWxEnterpriseId();
        String name = dto.getExternalName();
        String externalUserid = dto.getExternalUserid();
        String avatar = dto.getAvatar();
        String unionId = dto.getUnionid();
        //新增导购和外部联系人关系
        String clerkId = staffClerkRelationDTO.getClerkId();
        String clerkCode = staffClerkRelationDTO.getClerkCode();
        String enterpriseId = staffClerkRelationDTO.getEnterpriseId();
        ClerkDTO clerk = clerkService.getClerkByClerkCode(enterpriseId, clerkCode);
        log.info("【新增外部联系人】创建member,clerkCode={},unionid:{}", clerkCode, unionId);
        if (clerk == null) {
            log.info("【新增外部联系人】创建member,导购为空返回:{}", clerkCode);
            return "";
        }
        String qrcodeParam = clerk.getQrcodeParam();
        if (StringUtils.isBlank(qrcodeParam)) {
            log.info("导购码不存在：" + clerkCode);
            qrcodeParam = "clerk_clerk_"+clerk.getClerkId() ;
        }
        String memberId = null ;
        if (StringUtils.isNotBlank(mobile)) {
            memberId = memberService.getMemberIdByPhoneNumber(mobile, enterpriseId);
        }
        if (null == memberId) {
            memberId  = this.getMeberId(enterpriseId,unionId, name, avatar, qrcodeParam, externalUserid, wxEnterpriseRelated.getWxEnterpriseType(), 2) ;
        }
        if (memberId == null) {
            log.info("新增外部联系人,创建member失败,unionid={},外部联系人id={},", unionId,externalUserid);
            return "";
        }
        String storeId = staffClerkRelationDTO.getStoreId();
        this.saveExternalClerk(memberId, staffId, dto, staffClerkRelationDTO , 1);
        // this.sendWelcome(dto, qwDTO, enterpriseId, staffId, clerkId,memberId);
        //同步好友标签
        this.pushTagSync(memberId, wxEnterpriseId, enterpriseId);
        //回调给会员，更新是否为企微好友
        log.info("通知会员 合并会员后更新为企微好友,memberId:{}", memberId);
        this.memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 1);
        //定制事件订阅
        addDelFriendEvent(unionId, clerkId, wxEnterpriseId, enterpriseId, memberId, storeId, 1);
        return memberId;
    }
    private void saveExternalClerk(String memberId ,String staffId , MemberUnionidRelatedDTO dto , StaffClerkRelationDTO staffClerkRelation , int status) {
        String wxEnterpriseId = dto.getWxEnterpriseId() ;
        String externalUserid = dto.getExternalUserid();
        String relationKey = SecureUtil.md5(staffId + externalUserid);
        String memberUnionidRelatedId = dto.getMemberUnionidRelatedId();
        String name = dto.getExternalName();
        String createTime = dto.getAddCreateTime();
        String avatar = dto.getAvatar();
        String unionId = dto.getUnionid();
        String enterpriseId = staffClerkRelation.getEnterpriseId() ; 
        String clerkId = staffClerkRelation.getClerkId() ;
        String storeId = staffClerkRelation.getStoreId();
        List<TabHaobanExternalClerkRelated> externalList = externalClerkRelatedService.listByExTernalUseridAndWxUserIdAllStatus(wxEnterpriseId, externalUserid, staffId);
        if(CollectionUtils.isEmpty(externalList)) {
            log.info("新增好友表");
            TabHaobanExternalClerkRelated related = new TabHaobanExternalClerkRelated();
            related.setAddCreateTime(createTime);
            related.setClerkId(clerkId);
            related.setEnterpriseId(enterpriseId);
            related.setExternalName(name);
            related.setExternalUserId(externalUserid);
            related.setSelfExternalUserid(dto.getSelfExternalUserid());
            related.setStaffId(staffId);
            related.setHeadUrl(avatar);
            related.setMemberUnionidRelatedId(memberUnionidRelatedId);
            related.setStoreId(storeId);
            related.setRelationKey(relationKey);
            related.setUnionid(unionId);
            related.setWxEnterpriseId(wxEnterpriseId);
            related.setMemberId(memberId);
            related.setStatusFlag(status);
            if(status==4) {
               related.setPushTimes(1);
            }
            this.externalClerkRelatedService.insert(related);
        }else {
            TabHaobanExternalClerkRelated exsitDTO = externalList.get(0);
            log.info("更新好友表,{},{}",exsitDTO.getExternalUserId(),exsitDTO.getStatusFlag());
            if(exsitDTO.getStatusFlag()==1) {
                return ;
            }
            exsitDTO.setMemberUnionidRelatedId(memberUnionidRelatedId);
            exsitDTO.setRelationKey(relationKey);
            exsitDTO.setHeadUrl(avatar);
            exsitDTO.setMemberId(memberId);
            exsitDTO.setUnionid(unionId);
            exsitDTO.setStoreId(storeId);
            exsitDTO.setClerkId(clerkId);
            exsitDTO.setEnterpriseId(enterpriseId);
            if(StringUtils.isNotBlank(exsitDTO.getMemberId()) && exsitDTO.getStatusFlag() != 1) {
                exsitDTO.setStatusFlag(1);
            }
            this.externalClerkRelatedService.update(exsitDTO);
        }
    }
    
    /**
     * 欧泊莱定制需求
     */
    private void addDelFriendEvent(String unionId, String clerkId, String wxEnterpriseId, String enterpriseId, String memberId, String storeId, Integer changeType) {
        String addDelFriendEvent = config.getAddDelFriendEvent();
        if (!addDelFriendEvent.contains(wxEnterpriseId)) {
            log.info("非定制，无需广播通知");
            return;
        }

        if (StringUtils.isBlank(memberId)) {
            log.info("会员不存在:{}", memberId);
            return;
        }
        log.info("欧泊莱定制：推送会员,memberId：{},changeType:{}", memberId, changeType);
        //欧泊莱定制需求
        ClerkDTO clerkDTO = clerkService.getClerkByClerkIdNoStatus(clerkId);
        StoreDTO storeDTO = storeService.getStore(storeId);
        MemberDTO member = memberService.getMember(memberId);
        if (member == null) {
            log.info("会员不存在:{}", memberId);
            return;
        }
        GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
        try {
            JSONObject msgBody = new JSONObject();
            msgBody.put("cardNo", member.getCardNum());
            msgBody.put("enterpriseId", enterpriseId);
            msgBody.put("unionid", unionId);
            if (storeDTO != null) {
                msgBody.put("storeName", storeDTO.getStoreName());
                msgBody.put("storeCode", storeDTO.getStoreCode());
            }
            if (clerkDTO != null) {
                msgBody.put("clerkName", clerkDTO.getClerkName());
                msgBody.put("clerkCode", clerkDTO.getClerkCode());
            }
            // 1添加；0删除
            msgBody.put("changeType", changeType);
            if (changeType == 0) {
                msgBody.put("delCreateTime", new Date());
                msgBody.put("delUserContact", 1);
            } else {
                msgBody.put("addCreateTime", new Date());
            }
            //获取渠道
            List<String> list = new ArrayList<>();
            MemberSourceShowDTO memberSourceShowDTO = memberEntranceApiService.getMemberSourceByMemberId(enterpriseId, memberId);
            if (memberSourceShowDTO != null && CollectionUtils.isNotEmpty(memberSourceShowDTO.getMemberSourceList())) {
                for (MemberSourceDetailDTO memberSourceDetailDTO : memberSourceShowDTO.getMemberSourceList()) {
                    if (null != memberSourceDetailDTO.getHighlight() && memberSourceDetailDTO.getHighlight() == 1) {
                        list.add(memberSourceDetailDTO.getParentSourceCode());
                    }
                }
            }
            SubscribeMessageDTO subscribeMessageDTO = new SubscribeMessageDTO();
            subscribeMessageDTO.setEvent("addDelFriendEvent");
            subscribeMessageDTO.setTopic("member");
            subscribeMessageDTO.setEnterpriseId(enterpriseId);
            subscribeMessageDTO.setMemberId(memberId);
            subscribeMessageDTO.setMemberChannels(list);
            subscribeMessageDTO.setMsgBody(msgBody.toJSONString());
            clientInstance.sendMessage("dealQywxExternalUserEvent", JSONObject.toJSONString(subscribeMessageDTO));
        } catch (Exception e) {
            log.info("加好友事件订阅通知：{}", e.getMessage(), e);
        }
    }


    /**
     * 欢迎语新增好友
     *
     * @param dto
     */
    private void addFriendByWelcome(MemberUnionidRelatedDTO dto, StaffClerkRelationDTO staffClerkRelationDTO,WxEnterpriseQwDTO qwDTO) {
        String staffId = staffClerkRelationDTO.getStaffId();
        //发送欢迎语
        // sendWelcome(dto, qwDTO, enterpriseId, staffId, clerkId,null);
        //保存好友关系
        this.saveExternalClerk(null, staffId, dto, staffClerkRelationDTO, 4);
    }
    /**
     * 组装数据
     *
     * @param dto
     * @return
     */
    private MemberUnionidRelatedDTO getMemberUnionidRelatedDTONew(MemberUnionidRelatedDTO dto, String wxUserId) {
        log.info("【新增外部联系人】dto={},wxUserId={}", JSON.toJSONString(dto), wxUserId);
        String wxEnterpriseId = dto.getWxEnterpriseId() ;
        String suiteid = dto.getSuiteid();
        String externalUserid = dto.getExternalUserid();
        ExternalUserDTO externalUserDTO;
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId) ;
        if(qwDTO.isSelf() && dto.getSelfCallback()==0) {
            log.info("非自建应用回调");
            return null ;
        }
        if(qwDTO.isSelf()) {
            String unionIdJson = qywxUserApiService.getCorpSelfExternalUseridInfo(qwDTO.getDkCorpid(), qwDTO.getSelfSecret(), dto.getExternalUserid(),qwDTO.getUrlHost());
            if (StringUtils.isBlank(unionIdJson)) {
                log.info("好友不存在");
                return null;
            } else if ("1".equals(unionIdJson)) {
                log.info("接口调用被限制");
                throw new WxApiLimitException("getCorpSelfExternalUseridInfo接口调用被限制");
            }
            ExternalUserPojo pojo = getExternalUserPojo(unionIdJson, wxUserId, wxEnterpriseId);
            externalUserDTO = EntityUtil.changeEntityByJSON(ExternalUserDTO.class, pojo);
            if (externalUserDTO == null) {
                log.info("【新增外部联系人】查询好友失败,externalUserid={}",externalUserid);
                return null;
            }
            if(null != externalUserDTO.getFriendType() && 2==externalUserDTO.getFriendType()) {
                log.info("【新增外部联系人】忽略-2表示该外部联系人是企业微信用户,externalUserid={}",externalUserid);
                return null;
            }
            dto.setWxEnterpriseId(wxEnterpriseId);
            dto.setExternalName(EmojiFilterUtil.removeAllEmoji(externalUserDTO.getName()));
            dto.setAddCreateTime(externalUserDTO.getAddCreateTime());
            if(StringUtils.isNotEmpty(externalUserDTO.getAvatar())) {
                dto.setAvatar(externalUserDTO.getAvatar());
            }
            if(StringUtils.isNoneBlank(externalUserDTO.getUnionId())) {
                dto.setUnionid(externalUserDTO.getUnionId());
            }
            dto.setSelfExternalUserid(dto.getExternalUserid());
            return dto;
        }
        
        if (SELF_APP.equals(suiteid)) {
            externalUserDTO = this.getCorpSelfExternalUseridInfo(wxEnterpriseId, wxUserId, externalUserid);
        } else {
            externalUserDTO = this.getExternalUseridInfo(wxEnterpriseId, wxUserId, externalUserid);
        }
        checkQywxSettingApiService.saveFriendCallback(wxEnterpriseId, externalUserDTO, dto);
        if (externalUserDTO == null) {
            log.info("【新增外部联系人】查询好友失败,externalUserid={}",externalUserid);
            return null;
        }
        if(null != externalUserDTO.getFriendType() && 2==externalUserDTO.getFriendType()) {
            log.info("【新增外部联系人】忽略-2表示该外部联系人是企业微信用户,externalUserid={}",externalUserid);
            return null;
        }
        dto.setWxEnterpriseId(wxEnterpriseId);
        dto.setExternalName(EmojiFilterUtil.removeAllEmoji(externalUserDTO.getName()));
        dto.setAddCreateTime(externalUserDTO.getAddCreateTime());
        if(StringUtils.isNotEmpty(externalUserDTO.getAvatar())) {
            dto.setAvatar(externalUserDTO.getAvatar());
        }
        if(StringUtils.isNoneBlank(externalUserDTO.getUnionId())) {
            dto.setUnionid(externalUserDTO.getUnionId());
        }
        if (SELF_APP.equals(suiteid)) {
            dto.setSelfExternalUserid(externalUserDTO.getExternalUserId());
            // 代开发回调过来的外部联系人id设置null
            dto.setExternalUserid(null);
        } else {
            dto.setExternalUserid(externalUserDTO.getExternalUserId());
        }
        String key = "external" + dto.getWxEnterpriseId() + "_" + dto.getExternalName() + "_" + dto.getAddCreateTime();
        String lockKey = key + "-lock";
        RedisUtil.lock(lockKey, 10L);
        MemberUnionidRelatedDTO cacheDTO = RedisUtil.getCache(key, MemberUnionidRelatedDTO.class);
        if (cacheDTO == null) {
            log.info("只收到一个回调,数据写入缓存后返回={}", JSON.toJSONString(dto));
            RedisUtil.setCache(key, dto, 180L);
            RedisUtil.unlock(lockKey);
            return null;
        }
        
        dto.setUnionid(StringUtils.isBlank(dto.getUnionid()) ? cacheDTO.getUnionid() : dto.getUnionid());
        dto.setAvatar(StringUtils.isBlank(dto.getAvatar()) ? cacheDTO.getAvatar() : dto.getAvatar());
        dto.setExternalUserid(StringUtils.isBlank(dto.getExternalUserid()) ? cacheDTO.getExternalUserid() : externalUserid);
        dto.setSelfExternalUserid(StringUtils.isBlank(dto.getSelfExternalUserid()) ? cacheDTO.getSelfExternalUserid() : dto.getSelfExternalUserid());

        if (StringUtils.isAnyBlank(dto.getExternalUserid(), dto.getSelfExternalUserid())) {
            log.error("新增外部联系人,只有一个外部联系人id,wxEnterpriseId：{}", wxEnterpriseId, dto.getExternalUserid());
            return null;
        }
        
        log.info("新增外部联系人,写unionid表数据={}", JSON.toJSONString(dto));
        String memberUnionidRelatedId = memberUnionRelatedService.addMemberUnionidRelated(dto);
        dto.setMemberUnionidRelatedId(memberUnionidRelatedId);
        RedisUtil.unlock(lockKey);
        RedisUtil.delCache(key);
        return dto;
    }


    private ExternalUserPojo getExternalUserPojo(String unionIdJson, String userId1, String wxEnterpriseId) {
        ExternalUserPojo pojo = new ExternalUserPojo();
        String unionId = "";
        String follow_user = "";
        String createTime = "";
        String userId = "";
        String avatar = "";
        String relaName = "";
        String externalUserId = "";
        String state = "";
        int friendType = 1;
        if (StringUtils.isNotBlank(unionIdJson)) {
            JSONObject jo = JSON.parseObject(unionIdJson);
            String external_contact = jo.getString("external_contact");
            if (StringUtils.isNotBlank(external_contact)) {
                JSONObject jt = JSON.parseObject(external_contact);
                unionId = jt.getString("unionid");
                relaName = EmojiFilterUtil.filterEmojiLast(jt.getString("name"), true);
                if (StringUtils.isBlank(relaName)) {
                    relaName = "--";
                }
                avatar = jt.getString("avatar");
                friendType = jt.getInteger("type");
                externalUserId = jt.getString("external_userid");
            }

            follow_user = jo.getString("follow_user");
            if (StringUtils.isNotBlank(follow_user)) {
                JSONArray j = JSON.parseArray(follow_user);
                for (Object object : j) {
                    String followJson = JSON.toJSONString(object);
                    JSONObject follow = JSON.parseObject(followJson);
                    userId = follow.getString("userid");
                    state = follow.getString("state");
                    if (userId.equals(userId1)) {
                        createTime = follow.getString("createtime");
                    }
                }
            }
        }
        pojo.setAddCreateTime(createTime);
        pojo.setAvatar(avatar);
        pojo.setName(relaName);
        pojo.setUnionId(unionId);
        pojo.setExternalUserId(externalUserId);
        pojo.setWxEnterpriseId(wxEnterpriseId);
        pojo.setState(state);
        pojo.setFriendType(friendType);
        return pojo;
    }

    @Override
    public void delMemberUnionidRelated(QwFrientNoticeDTO dto) {
        DealQywxExternalUserPojo dealQywxExternalUserPojo = new DealQywxExternalUserPojo();
        dealQywxExternalUserPojo.setType(DealQywxExternalUserPojo.DealType.del.getType());
        dealQywxExternalUserPojo.setData(dto);

        GicMQClient instance = GICMQClientUtil.getClientInstance();
        try {
            instance.sendMessage("dealQywxExternalUserMq3", JSONObject.toJSONString(dealQywxExternalUserPojo));
        } catch (Exception e) {
            log.info("异步处理异常：{}", e);
        }
    }

    @Override
    public void editMemberUnionidRelated(QwFrientNoticeDTO dto) {
        DealQywxExternalUserPojo dealQywxExternalUserPojo = new DealQywxExternalUserPojo();
        dealQywxExternalUserPojo.setType(DealQywxExternalUserPojo.DealType.edit.getType());
        dealQywxExternalUserPojo.setData(dto);

        GicMQClient instance = GICMQClientUtil.getClientInstance();
        try {
            instance.sendMessage("dealQywxExternalUserMq3", JSONObject.toJSONString(dealQywxExternalUserPojo));
        } catch (Exception e) {
            log.info("异步处理异常：{}", e);
        }
    }

    /**
     * 删除好友
     *
     * @param dto
     */
    private void delMemberUnionidRelatedProcess(MemberUnionidRelatedDTO dto, String wxUserId) {
        String corpId = dto.getCorpid();
        TabHaobanWxEnterprise wxEnterprise = this.wxEnterpriseService.getEnterpriseBycorpId(corpId);
        if (wxEnterprise == null) {
            log.info("查询TabHaobanWxEnterprise为空：{}", corpId);
            return;
        }
        String wxEnterpriseId = wxEnterprise.getWxEnterpriseId();
        dto.setWxEnterpriseId(wxEnterpriseId);
        TabHaobanStaff staff = this.staffMapper.selectByUserIdAndEnterpriseId(wxUserId, wxEnterpriseId);
        if(null==staff) {
            log.info("成员未查到,userid={}",wxUserId);
            return ;
        }
        String staffId = staff.getStaffId();
        dto.setStaffId(staffId);
        externalClerkRelatedService.delByUserIdAndExternalUserId(dto);
    }

    private void editMemberUnionidRelatedProcess(MemberUnionidRelatedDTO dto, String wxUserId) {
        log.info("修改标签/会员信息回调：{}", JSONObject.toJSONString(dto));
        TabHaobanWxEnterprise wxEnterprise = wxEnterpriseService.getEnterpriseBycorpId(dto.getCorpid());
        if (null == wxEnterprise) {
            return;
        }
        if (dto.getSuiteid().equals(SELF_APP)) {
            log.info("self不执行");
            return;
        }
        pushTagSync(dto.getExternalUserid(), wxUserId
                , GicQywxSyncTypeEnum.FRIEND_TAG_SYNC.getType(), QywxSyncTaskTypeEnum.MEMBER_SYNC.getType(), wxEnterprise.getWxEnterpriseId(), null);
    }

    @Override
    public ExternalClerkRelatedDTO getByMemberId(String staffId, String memberId) {
        log.info("【查询会员】wxUserId={},memberId={}", staffId, memberId);
        return externalClerkRelatedService.getByMemberId(staffId, memberId);
    }

    /**
     * 创建企业群发, 支出素材批量发送
     * @param wxEnterpriseId : 微信企业id
     * @param userId         : 用户id
     * @param extendUserList : 发送的用户id
     * @param materialIdList : 素材id列表
     * @return : 返回群发执行结果
     */
    @Override
    public JSONResponse sendMessage(String wxEnterpriseId, String staffId, List<String> extendUserList, List<String> materialIdList, String planId) {
        com.gic.api.base.commons.ServiceResponse<String> resp = this.qywxSendService.sendMessage(wxEnterpriseId, staffId, extendUserList, materialIdList) ;
        return this.retJson(resp) ;
    }
    
    @Override
    public JSONResponse sendMessageShare(String wxEnterpriseId, String staffId, List<String> extendUserList, String message,
            List<ContentMaterialDTO> imgList) {
        com.gic.api.base.commons.ServiceResponse<String> resp = this.qywxSendService.sendMessageShare(wxEnterpriseId, staffId, extendUserList, imgList, message) ;
        return this.retJson(resp) ;
    }
    
    @Override
    public JSONResponse share(String wxEnterpriseId, List<String> clerkIdList, String message,
            List<ContentMaterialDTO> imgList) {
        com.gic.api.base.commons.ServiceResponse<String> resp = this.qywxSendService.share(wxEnterpriseId, clerkIdList, message, imgList) ;
        return this.retJson(resp) ;
    }
    
    private JSONResponse retJson(com.gic.api.base.commons.ServiceResponse<String> resp) {
        JSONResponse json = new JSONResponse();
        if(!resp.isSuccess()) {
            String code = resp.getCode() ;
            if(NumberUtil.isNumber(code) && !"1".equals(code)) {
                json.setErrorCode(Integer.valueOf(resp.getCode()));
            }else {
                json.setErrorCode(-1);
            }
            json.setErrorMessage(resp.getMessage());
        }else {
            json.setSuccess(true);
            json.setErrorCode(1);
            Map<String, Object> returnMap = new HashMap<String, Object>();
            returnMap.put("msgid",resp.getResult());
            json.setReturnMap(returnMap);
        }
        return json ;
    }
    
    /**
     * 获取群发成员发送任务列表
     *
     * @param wxEnterpriseId : 微信企业id
     * @param wxMessageId    : 消息id
     * @param cursor         : 分页游标
     * @return : 返回请求结果
     */
    @Override
    public JSONResponse taskExternalMessage(String wxEnterpriseId, String wxMessageId, String cursor) {
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            return null;
        }
        return qywxSuiteApiService.taskExternalMessage(qwDTO.getThirdCorpid(), qwDTO.getSelf3thSecret(), wxMessageId, cursor ,qwDTO.isSelf(),qwDTO.getUrlHost());
    }

    /**
     * 获取企业群发成员执行结果
     *
     * @param wxEnterpriseId : 微信企业id
     * @param wxMessageId    : 消息id
     * @param cursor         : 分页游标
     * @param userId         : 用户id
     * @return : 返回请求结果
     */
    @Override
    public JSONResponse resultExternalMessage(String wxEnterpriseId, String wxMessageId, String cursor, String userId) {
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            return null;
        }
        if(qwDTO.isSelf()) {
            return qywxSuiteApiService.resultExternalMessageSelf(qwDTO.getThirdCorpid(), qwDTO.getSelfSecret(),
                    wxMessageId, cursor, userId, qwDTO.getUrlHost());
        }else {
            return qywxSuiteApiService.resultExternalMessage(qwDTO.getThirdCorpid(), config.getWxSuiteid(),
                    wxMessageId, cursor, userId);
        }
    }

    @Override
    public JSONResponse getMessageStatus(String wxEnterpriseId, String wxMessageId) {
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            return null;
        }
        return qywxSuiteApiService.resultExternalMessage(qwDTO.getThirdCorpid(),  qwDTO.getSelf3thSecret(), wxMessageId , qwDTO.isSelf(),qwDTO.getUrlHost());
    }

    @Override
    public List<String> listSelfExterialList(String wxEnterpriseId, String wxUserId) {
        try {
            log.info("【查询代开应用好友】wxEnterpriseId={},wxUserId={}", wxEnterpriseId, wxUserId);
            WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
            List<String> list = new ArrayList<>();
            SecretSettingDTO secretSetting = secretSettingService.getSecretSetting(wxEnterpriseId, SecretTypeEnum.CUSTOMIZED_APP.getVal());
            if (null == secretSetting || secretSetting.getCheckFlag() == 0) {
                log.info("没有配置客户联系secret:{}", wxEnterpriseId);
                return list;
            }
            String res = qywxUserApiService.listSelfExternalUserid(qwDTO.getDkCorpid(), secretSetting.getSecretVal(), wxUserId,qwDTO.getUrlHost());
            log.info("【查询自建应用】res={}", res);
            if (res != null && res.equals("1")) {
                log.info("代表需要重试");
                return null;
            }
            if (StringUtils.isBlank(res)) {
                return list;
            }
            JSONArray jsonArr = JSON.parseArray(res);
            if (jsonArr.size() == 0) {
                return list;
            }
            for (Object object : jsonArr) {
                list.add(object.toString());
            }
            return list;
        } catch (Exception e) {
            log.info("错误={}", e);
        }
        return null;
    }

    @Override
    public List<String> listExterialList(String wxEnterpriseId, String wxUserId) {
        log.info("【获取第三方应用好友】wxEnterpriseId={},wxUserId={}", wxEnterpriseId, wxUserId);
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        String corpid = qwDTO.getThirdCorpid();
        String userId = "";
        TabHaobanStaff staff = staffService.selectByUserIdAndEnterpriseId(wxUserId, wxEnterpriseId);
        if (staff == null) {
            log.error("员工为空，wxUserId：{}", wxUserId);
            return null;
        }
        if (qwDTO.needOpenUserId3th()) {
            userId = staff.getWxOpenUseId();
        } else {
            userId = staff.getWxUserId();
        }
        log.info("【获取第三方应用好友】wxEnterpriseId={},userId={}", wxEnterpriseId, userId);
        String wxRes = qywxUserApiService.listExternalUserid(corpid, config.getWxSuiteid(), userId);
        List<String> list = new ArrayList<>();
        log.info("【查询第三方应用】res={}", wxRes);
        if ("1".equals(wxRes)) {
            log.info("代表需要重试");
            return null;
        }
        if (StringUtils.isBlank(wxRes)) {
            return list;
        }
        JSONArray jsonArr = JSON.parseArray(wxRes);
        if (jsonArr.size() == 0) {
            return list;
        }
        for (Object object : jsonArr) {
            list.add(object.toString());
        }
        return list;
    }

    @Override
    public ExternalUserDTO getCorpSelfExternalUseridInfo(String wxEnterpriseId, String wxUserId, String externalUserId) {
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            log.info("企业不存在");
            return null;
        }
        SecretSettingDTO secretSetting = secretSettingService.getSecretSetting(wxEnterpriseId, SecretTypeEnum.CUSTOMIZED_APP.getVal());
        if (null == secretSetting) {
            log.info("没有配置secret");
            return null;
        }
        String unionIdJson = qywxUserApiService.getCorpSelfExternalUseridInfo(qwDTO.getDkCorpid(), secretSetting.getSecretVal(), externalUserId,qwDTO.getUrlHost());
        if (StringUtils.isBlank(unionIdJson)) {
            log.info("好友不存在");
            return null;
        } else if ("1".equals(unionIdJson)) {
            log.info("接口调用被限制");
            throw new WxApiLimitException("getCorpSelfExternalUseridInfo接口调用被限制");
        }
        ExternalUserPojo pojo = getExternalUserPojo(unionIdJson, wxUserId, wxEnterpriseId);
        return EntityUtil.changeEntityByJSON(ExternalUserDTO.class, pojo);
    }

    @Override
    public ExternalUserDTO getCorpSelfExternalUseridInfoForMember(String wxEnterpriseId, String wxUserId,
                                                                  String externalUserId, String enterpriseId) {
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            log.info("企业不存在");
            return null;
        }
        SecretSettingDTO secretSetting = secretSettingService.getMemberSecretSetting(wxEnterpriseId, enterpriseId);
        if (null == secretSetting) {
            log.info("没有配置secret");
            return null;
        }
        String unionIdJson = qywxUserApiService.getCorpSelfExternalUseridInfo(qwDTO.getMemberCorpid(), secretSetting.getSecretVal(), externalUserId,qwDTO.getUrlHost());
        if (StringUtils.isBlank(unionIdJson)) {
            log.info("好友不存在");
            return null;
        } else if ("1".equals(unionIdJson)) {
            log.info("接口调用被限制");
            throw new WxApiLimitException("getCorpSelfExternalUseridInfo接口调用被限制");
        }
        ExternalUserPojo pojo = getExternalUserPojo(unionIdJson, wxUserId, wxEnterpriseId);
        return EntityUtil.changeEntityByJSON(ExternalUserDTO.class, pojo);
    }

    @Override
    public ExternalUserDTO getExternalUseridInfo(String wxEnterpriseId, String wxUserId, String externalUserId) {
        log.info("查询第三方:wxEnterpriseId:{},wxUserId:{},externalUserId:{}", wxEnterpriseId, wxUserId, externalUserId);
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            log.info("企业不存在");
            return null;
        }
        TabHaobanStaff tabHaobanStaff = staffService.selectByUserIdAndEnterpriseId(wxUserId, wxEnterpriseId);
        if (tabHaobanStaff == null) {
            log.info("员工不存在，wxUserId：{}", wxUserId);
            return null;
        }
        String wxOpenUseId = tabHaobanStaff.getWxOpenUseId();
        String uJ = null ;
        if(qwDTO.isSelf()) {
            uJ = this.qywxUserApiService.getCorpSelfExternalUseridInfo(qwDTO.getDkCorpid(), qwDTO.getSelfSecret(), externalUserId,qwDTO.getUrlHost()) ;
        }else {
            uJ = this.qywxUserApiService.getExternalUseridInfo(qwDTO.getThirdCorpid(), config.getWxSuiteid(), externalUserId);
        }
        if (StringUtils.isBlank(uJ)) {
            log.info("好友不存在");
            return null;
        } else if ("1".equals(uJ)) {
            log.info("限制次数");
            throw new WxApiLimitException("getExternalUseridInfo接口次数限制");
        }
        String name = "";
        String createTime = "";
        String avatar = "";
        Integer friendType = 1;
        String state = "";
        if (StringUtils.isNotBlank(uJ)) {
            JSONObject jo = JSON.parseObject(uJ);
            String external_contact = jo.getString("external_contact");
            String uj_follow_user = jo.getString("follow_user");
            JSONObject jt = null;
            if (StringUtils.isNotBlank(external_contact)) {
                jt = JSON.parseObject(external_contact);
                name = EmojiFilterUtil.filterEmojiLast(jt.getString("name"), true);
                if (StringUtils.isBlank(name)) {
                    name = "--";
                }
                friendType = jt.getInteger("type");
                avatar = jt.getString("avatar");
            }
            if (StringUtils.isNotBlank(uj_follow_user)) {
                JSONArray j = JSON.parseArray(uj_follow_user);
                String uj_userId = "";
                for (Object object : j) {
                    String followJson = JSON.toJSONString(object);
                    JSONObject follow = JSON.parseObject(followJson);
                    uj_userId = follow.getString("userid");
                    state = follow.getString("state");
                    //第三方返回的是加密的，多做一层判断
                    if (uj_userId.equals(wxUserId) || uj_userId.equals(wxOpenUseId)) {
                        if (jt != null) {
                            externalUserId = jt.getString("external_userid");
                            createTime = follow.getString("createtime");
                            break;
                        }
                    }
                }
            }
        }
        ExternalUserPojo pojo = new ExternalUserPojo();
        pojo.setExternalUserId(externalUserId);
        pojo.setName(name);
        pojo.setAddCreateTime(createTime);
        pojo.setWxEnterpriseId(wxEnterpriseId);
        pojo.setAvatar(avatar);
        pojo.setFriendType(friendType);
        pojo.setState(state);
        return EntityUtil.changeEntityByJSON(ExternalUserDTO.class, pojo);
    }

    private String saveExternalUser(ExternalUserDTO dto) {
        String wxEnterpriseId = dto.getWxEnterpriseId();
        String name = StringUtils.isBlank(dto.getName()) ? "--" : dto.getName();
        String createTime = dto.getAddCreateTime();
        String unionId = dto.getUnionId();
        String externalUserId = dto.getExternalUserId();
        String memberId = dto.getMemberId();
        String enterpriseId = dto.getEnterpriseId();
        String storeId = dto.getStoreId();
        String clerkId = dto.getClerkId();
        String staffId = dto.getStaffId();
        if (StringUtils.isAnyBlank(wxEnterpriseId, name, createTime, externalUserId, storeId, enterpriseId, staffId, clerkId)) {
            log.info("【刷新好友】参数有空wxUserId={},wxEnterpriseId={},name={},createTime={},unionId ={},externalUserId ={},memberId ={},storeId ={},enterpriseId ={},staffId={},clerkId={}"
                    + "", wxEnterpriseId, name, createTime, unionId, externalUserId, memberId, storeId, enterpriseId, staffId, clerkId);
            return "参数不对";
        }
        String memberUnionidRelatedId = this.saveMemberUnionTable(dto) ;
        StaffClerkRelationDTO staffClerkRelation = new StaffClerkRelationDTO() ;
        staffClerkRelation.setEnterpriseId(enterpriseId);
        staffClerkRelation.setStoreId(storeId);
        staffClerkRelation.setClerkId(clerkId);
        MemberUnionidRelatedDTO unionDTO = EntityUtil.changeEntityByJSON(MemberUnionidRelatedDTO.class, dto) ;
        unionDTO.setExternalName(dto.getName());
        unionDTO.setExternalUserid(dto.getExternalUserId());
        unionDTO.setSelfExternalUserid(dto.getSelfExternalUserId());
        unionDTO.setMemberUnionidRelatedId(memberUnionidRelatedId);
        int statusFlag = 1 ;
        if(StringUtils.isBlank(memberId)) {
            statusFlag = 3 ;
        }
        this.saveExternalClerk(memberId, staffId, unionDTO, staffClerkRelation, statusFlag);
        if(StringUtils.isNotBlank(memberId)) {
            this.pushTagSync(memberId, wxEnterpriseId, enterpriseId);
            log.info("通知会员 更新为企微好友 memberId:{}", memberId);
            memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 1);
        }
        return "";
    }
    
    /**
     * 同步
     */
    private void pushTagSync(String dataId, String taskId, int syncType, int taskType, String wxEnterpriseId, String enterpriseId) {
        QywxTagSyncInfoPojo pojo = new QywxTagSyncInfoPojo();
        pojo.setDataId(dataId);
        pojo.setTaskId(taskId);
        pojo.setTaskType(taskType);
        //单个会员同步
        pojo.setSyncType(syncType);
        pojo.setWxEnterpriseId(wxEnterpriseId);
        pojo.setEnterpriseId(enterpriseId);
        GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
        try {
            clientInstance.sendMessage("qywxTagSyncDeal", JSONObject.toJSONString(pojo));
        } catch (Exception e) {
            log.info("异常：{}", e);
        }
    }

    /**
     * 同步
     */
    private void pushTagSync(String memberId, String wxEnterpriseId, String enterpriseId) {
        this.pushTagSync(memberId, "-1", GicQywxSyncTypeEnum.SINGLE_WXENT_MEMNER_SYNC.getType(), QywxSyncTaskTypeEnum.MEMBER_SYNC.getType(), wxEnterpriseId, enterpriseId);
    }

    private String saveMemberUnionTable(ExternalUserDTO dto) {
        String wxEnterpriseId = dto.getWxEnterpriseId();
        String name = dto.getName();
        String createTime = dto.getAddCreateTime();
        String externalUserId = dto.getExternalUserId();
        String staffId = dto.getStaffId();
        String avatar = dto.getAvatar();
        MemberUnionidRelatedDTO   exsitDTO = new MemberUnionidRelatedDTO();
        exsitDTO.setAvatar(avatar);
        exsitDTO.setExternalUserid(externalUserId);
        exsitDTO.setSelfExternalUserid(dto.getSelfExternalUserId());
        exsitDTO.setAddCreateTime(createTime);
        exsitDTO.setExternalName(name);
        exsitDTO.setWxEnterpriseId(wxEnterpriseId);
        exsitDTO.setStaffId(staffId);
        return  memberUnionRelatedService.addMemberUnionidRelated(exsitDTO);
    }
    
    @Override
    public void cleanNoExsitFriendNew(String wxEnterpriseId, String staffId, List<String> externalUserIds) {
        log.info("开始删除无效的外部联系人,wxEnterpriseId={},staffId={}", wxEnterpriseId, staffId);
        //查询所有的外部联系人
        List<TabHaobanExternalClerkRelated> list = externalClerkRelatedMapper.getByWxUserIdAndWxEnterpriseId(wxEnterpriseId, staffId);
        if (CollectionUtils.isEmpty(list)) {
            log.info("导购下没有外部联系人，无需处理,{}", staffId);
            return;
        }
        Set<String> externalUserIdList = list.stream().map(external -> external.getExternalUserId()).collect(Collectors.toSet());
        Sets.SetView<String> delExternalUserIds = Sets.difference(new HashSet<>(externalUserIds), externalUserIdList);
        if (CollectionUtils.isEmpty(delExternalUserIds)) {
            log.info("没有需要删除的外部联系人:{}", staffId);
            return;
        }
        //删除成员与union的关联关系
        List<String> khList = new ArrayList<String>(delExternalUserIds);
        log.info("需要删除外部联系人staffId={} , khList={}", staffId, JSON.toJSONString(khList));
        //删除导购和外部联系人关系
        externalClerkRelatedService.delByUserIdAndExternalUserIdBatch(wxEnterpriseId, staffId, khList);
    }

    @Override
    public ServiceResponse<List<FriendStoreInfoDTO>> listFriendClerkByMemberUnionid(String enterpriseId, String unionId) {
        ServiceResponse<List<FriendStoreInfoDTO>> resp = new ServiceResponse<>();
        if (StringUtils.isAnyBlank(enterpriseId, unionId)) {
            resp.setMessage("参数有误");
            resp.setCode(2);
            return resp;
        }
        List<TabHaobanExternalClerkRelated> relateds = externalClerkRelatedService.listExternalByUnionId(enterpriseId, unionId);
        if (CollectionUtils.isEmpty(relateds)) {
            return resp;
        }
        //导购信息
        Set<String> clerkIds = relateds.stream().map(dto -> dto.getClerkId()).collect(Collectors.toSet());
        log.info("获取clerkIds：{}", JSONObject.toJSONString(clerkIds));
        List<ClerkDTO> clerkDTOS = clerkService.getClerkByIds(clerkIds);
        if (CollectionUtils.isEmpty(clerkDTOS)) {
            log.info("没有有效的导购");
            return resp;
        }
        Map<String, ClerkDTO> clerkMap = clerkDTOS.stream().collect(Collectors.toMap(ClerkDTO::getClerkId, dto -> dto));

        //门店信息
        List<String> storeIds = relateds.stream().map(dto -> dto.getStoreId()).collect(Collectors.toList());
        log.info("门店storeIds：{}", JSONObject.toJSONString(storeIds));
        List<StoreDTO> storeDTOS = storeService.queryStore(storeIds);
        if (CollectionUtils.isEmpty(storeDTOS)) {
            log.info("没有关联的门店");
            return resp;
        }
        Map<String, StoreDTO> storeMap = storeDTOS.stream().collect(Collectors.toMap(StoreDTO::getStoreId, dto -> dto));

        //组装
        log.info("组装返回的好友导购信息:{}", unionId);
        List<FriendStoreInfoDTO> ret = relateds.stream().map(related -> {
            ClerkDTO clerkDTO = clerkMap.get(related.getClerkId());
            StoreDTO storeDTO = storeMap.get(related.getStoreId());

            FriendStoreInfoDTO friendStoreInfoDTO = new FriendStoreInfoDTO();
            friendStoreInfoDTO.setAddFriendTime(related.getAddCreateTime());
            friendStoreInfoDTO.setClerkId(related.getClerkId());
            friendStoreInfoDTO.setStoreId(related.getStoreId());
            friendStoreInfoDTO.setWxUserId(null/*related.getWxUserId()*/);
            friendStoreInfoDTO.setStoreCode(storeDTO != null ? storeDTO.getStoreCode() : null);
            friendStoreInfoDTO.setStoreName(storeDTO != null ? storeDTO.getStoreName() : null);
            friendStoreInfoDTO.setClerkCode(clerkDTO != null ? clerkDTO.getClerkCode() : null);
            friendStoreInfoDTO.setClerkName(clerkDTO != null ? clerkDTO.getClerkName() : null);
            friendStoreInfoDTO.setClerkPhoneNumber(clerkDTO != null ? clerkDTO.getPhoneNumber() : null);
            return friendStoreInfoDTO;
        }).collect(Collectors.toList());
        resp.setResult(ret);
        return resp;
    }

    @Override
    public MemberUnionidRelatedDTO getBySelfExternalUserId(String wxEnterpriseId, String selfExternalUserId) {
        return memberUnionRelatedService.getBySelfExternalUserId(wxEnterpriseId, selfExternalUserId);
    }

    @Override
    public void addMemberUnionidWechatAccount(String res) {
        log.info("通过查询unionid关联导购对外联系人id接口,res:{}", res);
        if (StringUtils.isBlank(res)) {
            log.info("通过查询unionid关联导购对外联系人id接口为空");
            return;
        }
        MemberUnionidWechatAccountQDTO memberUnionidWechatAccountQDTO = JSON.parseObject(res, MemberUnionidWechatAccountQDTO.class);
        String enterpriseId = memberUnionidWechatAccountQDTO.getEnterpriseId();
        String unionid = memberUnionidWechatAccountQDTO.getUnionid();
        String openId = memberUnionidWechatAccountQDTO.getOpenId();
        String memberId = memberUnionidWechatAccountQDTO.getMemberId();
        if (StringUtils.isAnyBlank(enterpriseId, unionid, openId, memberId)) {
            log.error("关注公共号-会员回调好办关联好友 有参数为空:enterpriseId:{},unionid:{},openId:{},memberId:{}", enterpriseId, unionid, openId, memberId);
            return;
        }
        List<TabHaobanWxEnterprise> tabHaobanWxEnterprises = wxEnterpriseRelatedService.listByEnterpriseId(enterpriseId);
        if (CollectionUtils.isEmpty(tabHaobanWxEnterprises)) {
            log.error("企业为空");
            return;
        }

        RRateLimiter rateLimiter = RedisUtil.getRedisClient().getRateLimiter("member:weChat:add:limit");
        // 每1小时产生9500个令牌
        rateLimiter.trySetRate(RateType.OVERALL, 9500, 1, RateIntervalUnit.HOURS);
        for (TabHaobanWxEnterprise tabHaobanWxEnterpris : tabHaobanWxEnterprises) {
            if (!rateLimiter.tryAcquire()) {
                log.error("请求unionidToExternalUserid3rd超过限制，丢入消息队列，重新消费");
                GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
                try {
                    clientInstance.sendMessage("addMemberUnionidWechatAccountMq", res, 60 * 60);
                } catch (Exception e) {
                    log.info("addMemberUnionidWechatAccount 发送失败：{}", e.getMessage(), e);
                }
                return;
            }
            String wxEnterpriseId = tabHaobanWxEnterpris.getWxEnterpriseId();
            WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
            if(qwDTO.isSelf()) {
                continue ;
            }
            String corpid = qwDTO.getThirdCorpid();
            List<UnionidToExternalUseridDTO> unionidToExternalUseridDTOS = qywxUserApiService.unionidToExternalUserid3rd(unionid, openId, corpid, config.getWxSuiteid());
            if (CollectionUtils.isEmpty(unionidToExternalUseridDTOS)) {
                log.error("请求unionidToExternalUserid3rd返回为空");
                continue;
            }

            for (UnionidToExternalUseridDTO unionidToExternalUseridDTO : unionidToExternalUseridDTOS) {
                String externalUserid = unionidToExternalUseridDTO.getExternalUserid();
                List<ExternalUserDTO> externalUseridInfoList = getExternalUseridInfoList(wxEnterpriseId, externalUserid);
                if (CollectionUtils.isEmpty(externalUseridInfoList)) {
                    log.error("返回客户详情为空：wxEnterpriseId:{},externalUserid:{}", wxEnterpriseId, externalUserid);
                    break;
                }
                for (ExternalUserDTO externalUserDTO : externalUseridInfoList) {
                    String wxUserId = externalUserDTO.getWxUserId();
                    TabHaobanStaff tabHaobanStaff = staffService.selectByUserIdAndEnterpriseId(wxUserId, wxEnterpriseId);
                    if (tabHaobanStaff == null) {
                        log.error("员工不存在:{}", wxUserId);
                        continue;
                    }
                    TabHaobanExternalClerkRelated externalClerkRelated = externalClerkRelatedMapper.getByEnterpriseIdAndExternalUserId(wxEnterpriseId, tabHaobanStaff.getStaffId(), enterpriseId, externalUserid);
                    if (externalClerkRelated == null) {
                        log.info("查询不到好友wxEnterpriseId:{}, wxUserId:{}, enterpriseId:{}, externalUserid:{}", wxEnterpriseId, tabHaobanStaff.getStaffId(), enterpriseId, externalUserid);
                        continue;
                    }
                    boolean flag = externalClerkRelatedApiService.bindMemberIdExternalById(externalClerkRelated.getExternalClerkRelatedId(), enterpriseId, memberId, unionid);
                    if (flag) {
                        //调用会员接口来自企微
                        memberStoreService.saveMemberStoreClerkRelation(memberId, externalClerkRelated.getStoreId(), externalClerkRelated.getClerkId(), "企微好友");
                    }
                }
            }
        }
    }

    @Override
    public void addMemberUnionidWechatAccountByClerk(String res) {
        log.info("关注公共号-会员回调好办关联好友请求参数：{}", res);
        if (StringUtils.isBlank(res)) {
            log.info("关注公共号-会员回调好办关联好友请求参数为空");
            return;
        }
        MemberUnionidWechatAccountQDTO memberUnionidWechatAccountQDTO = JSON.parseObject(res, MemberUnionidWechatAccountQDTO.class);
        String enterpriseId = memberUnionidWechatAccountQDTO.getEnterpriseId();
        String unionid = memberUnionidWechatAccountQDTO.getUnionid();
        String openId = memberUnionidWechatAccountQDTO.getOpenId();
        String memberId = memberUnionidWechatAccountQDTO.getMemberId();
        String sceneStr = memberUnionidWechatAccountQDTO.getSceneStr();
        if (StringUtils.isAnyBlank(enterpriseId, unionid, openId, memberId, sceneStr)) {
            log.error("关注公共号-会员回调好办关联好友，有参数为空:enterpriseId:{},unionid:{},openId:{},memberId:{},sceneStr:{}", enterpriseId, unionid, openId, memberId, sceneStr);
            return;
        }
        String[] s = sceneStr.split("_");
        String relationKey = s[1];
        TabHaobanExternalClerkRelated externalClerkRelated = externalClerkRelatedMapper.getByRelationKey(relationKey,1);
        if (externalClerkRelated == null) {
            log.error("关注公共号-会员回调好办关联好友,未查询到,relationKey：{}", relationKey);
            //重试5次
            Integer currentTimes = Convert.toInt(RedisUtil.getCache(relationKey), 0);
            if (currentTimes > MAX_TIMES) {
                log.error("关注公共号-会员回调好办关联好友重试超过最大次数，relationKey：{}", relationKey);
                return;
            }
            GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
            try {
                clientInstance.sendMessage("addMemberUnionidWechatAccountByClerkMq", res, 180);
                RedisUtil.setCache(relationKey, currentTimes + 1, 2L, TimeUnit.HOURS);
            } catch (Exception e) {
                log.info("发送消息异常：{}", e.getMessage());
            }
            return;
        }
        externalClerkRelatedApiService.bindMemberIdExternalById(externalClerkRelated.getExternalClerkRelatedId(), enterpriseId, memberId, unionid);
    }


    /**
     * 获取客户详情列表
     *
     * @param wxEnterpriseId
     * @param externalUserId
     * @return
     */
    private List<ExternalUserDTO> getExternalUseridInfoList(String wxEnterpriseId, String externalUserId) {
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            log.info("企业不存在");
            return null;
        }
        String uJ = null ;
        if(qwDTO.isSelf()) {
            uJ = this.qywxUserApiService.getCorpSelfExternalUseridInfo(qwDTO.getDkCorpid(), qwDTO.getSelfSecret(), externalUserId,qwDTO.getUrlHost()) ;
        }else {
            uJ = this.qywxUserApiService.getExternalUseridInfo(qwDTO.getThirdCorpid(), config.getWxSuiteid(), externalUserId);
        }
        if (StringUtils.isBlank(uJ)) {
            log.info("好友不存在");
            return null;
        } else if ("1".equals(uJ)) {
            log.info("限制次数");
            throw new WxApiLimitException("getExternalUseridInfo接口次数限制");
        }
        String name = "";
        String createTime = "";
        String avatar = "";
        Integer friendType = 1;
        List<ExternalUserPojo> externalUserPojoList = new ArrayList<>();
        JSONObject jo = JSON.parseObject(uJ);
        String external_contact = jo.getString("external_contact");
        String uj_follow_user = jo.getString("follow_user");
        JSONObject jt = null;
        if (StringUtils.isNotBlank(external_contact)) {
            jt = JSON.parseObject(external_contact);
            name = EmojiFilterUtil.filterEmojiLast(jt.getString("name"), true);
            if (StringUtils.isBlank(name)) {
                name = "--";
            }
            friendType = jt.getInteger("type");
            avatar = jt.getString("avatar");
        }
        if (StringUtils.isNotBlank(uj_follow_user)) {
            JSONArray j = JSON.parseArray(uj_follow_user);
            String uj_userId = "";
            for (Object object : j) {
                ExternalUserPojo pojo = new ExternalUserPojo();
                String followJson = JSON.toJSONString(object);
                JSONObject follow = JSON.parseObject(followJson);
                uj_userId = follow.getString("userid");
                if (jt != null) {
                    externalUserId = jt.getString("external_userid");
                    createTime = follow.getString("createtime");
                }
                pojo.setExternalUserId(externalUserId);
                pojo.setName(name);
                pojo.setAddCreateTime(createTime);
                pojo.setWxEnterpriseId(wxEnterpriseId);
                pojo.setAvatar(avatar);
                pojo.setWxUserId(uj_userId);
                pojo.setFriendType(friendType);
                externalUserPojoList.add(pojo);
            }
        }
        return EntityUtil.changeEntityListByJSON(ExternalUserDTO.class, externalUserPojoList);
    }
    
    
    @Override
    public void saveExternalMemberLog(ExternalMemberLogDTO memberLog) {
        this.externalMemberService.insert(memberLog) ;
    }
    
    @Override   
    public String dealMergeForReflsh(ExternalUserDTO externalUserDTO, String wxEnterpriseId , String staffId) {
        if (externalUserDTO.getFriendType() == 2) {
            return "不是微信好友，是企业微信好友:" + externalUserDTO.getFriendType();
        }
        ClerkMainStoreRelatedDTO mainStore = clerkMainStoreRelatedApiService.getWxEnterpriseIdAndStaffId(wxEnterpriseId, staffId);
        if (mainStore == null) {
            return "主门店不存在";
        }
        StaffClerkRelationDTO staffClerkRelationDTO = staffClerkRelationService.getOneBindByStoreId(staffId, mainStore.getStoreId());
        if (staffClerkRelationDTO == null) {
            return "未绑定导购";
        }
        String enterpriseId = staffClerkRelationDTO.getEnterpriseId() ;
        TabHaobanWxEnterpriseRelated wxEnterpriseRelated = wxEnterpriseRelatedService.getByEnterpriseId(wxEnterpriseId, enterpriseId);
        if (wxEnterpriseRelated == null) {
            log.info("没有存在企业关联：{},{}", wxEnterpriseId, enterpriseId);
            return "没有关联企业"; 
        }
        String storeId = mainStore.getStoreId() ;
        String clerkId = staffClerkRelationDTO.getClerkId() ;
        externalUserDTO.setWxEnterpriseId(wxEnterpriseId);
        externalUserDTO.setEnterpriseId(enterpriseId);
        externalUserDTO.setStoreId(storeId);
        externalUserDTO.setClerkId(clerkId);
        externalUserDTO.setStaffId(staffId);

        boolean addByWelcome = this.wxEnterpriseRelatedService.getAddByWelcomeFlag(wxEnterpriseRelated,externalUserDTO.getUnionId(),false) ;
        if (addByWelcome) {
            log.info("好友不同开平：{}", JSONObject.toJSONString(externalUserDTO));
            return this.saveExternalUser(externalUserDTO);
        }
        String clerkCode = staffClerkRelationDTO.getClerkCode();
        ClerkDTO clerk = clerkService.getClerkByClerkCode(staffClerkRelationDTO.getEnterpriseId(), clerkCode);
        if (clerk == null) {
            return "导购不存在:" + clerkCode;
        }
        String qrcodeParam = clerk.getQrcodeParam();
        if (StringUtils.isBlank(qrcodeParam)) {
            log.info("导购码不存在：" + clerkCode);
            qrcodeParam = "clerk_clerk_"+clerk.getClerkId() ;
        }
        String memberId  = this.getMeberId(enterpriseId, externalUserDTO.getUnionId(), externalUserDTO.getName(), externalUserDTO.getAvatar(), qrcodeParam, externalUserDTO.getExternalUserId(), wxEnterpriseRelated.getWxEnterpriseType(), 1) ;
        if (memberId == null) {
            return "会员不存在:unionid:" + externalUserDTO.getUnionId();
        }
        externalUserDTO.setMemberId(memberId);
        return this.saveExternalUser(externalUserDTO);
    }
    
    private String getMeberId(String enterpriseId , String unionid , String name , String image ,String qrcodeParam , String externalUserId , int wxEnterpriseType , int sence) {
        QywxMemberQDTO qdto = new QywxMemberQDTO() ;
        qdto.setEnterpriseId(enterpriseId);
        qdto.setNick(name);
        qdto.setPhotoUrl(image);
        qdto.setQrcodeParam(qrcodeParam);
        qdto.setUnionId(unionid);
        if(wxEnterpriseType==0) {
            qdto.setUserId(externalUserId);
        }
        qdto.setSence(sence);
        String memberId = null;
        com.gic.api.base.commons.ServiceResponse<MemberSimpleDetailDTO> resp = this.memberEntranceApiService.enterpriseWechatByFriendEntrance(qdto);
        log.info("刷新好友,创建member,resp={},param={}",JSON.toJSON(resp),JSON.toJSONString(qdto));
        if(resp.isSuccess()) {
            MemberSimpleDetailDTO member = resp.getResult() ;
            memberId = member.getMemberId() ;
        }
        return memberId ;
    }
}
