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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.Page;
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.dubbo.entity.ProviderLocalTag;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.app.customer.enums.GicQywxSyncTypeEnum;
import com.gic.haoban.app.customer.enums.QywxSyncTaskTypeEnum;
import com.gic.haoban.base.api.common.BasePageInfo;
import com.gic.haoban.base.api.common.ServiceResponse;
import com.gic.haoban.base.api.common.errCode.HaoBanErrCodeCommon;
import com.gic.haoban.common.utils.PageUtil;
import com.gic.haoban.manage.api.dto.*;
import com.gic.haoban.manage.api.enums.AlertTypeEnum;
import com.gic.haoban.manage.api.enums.SyncTaskTypeEnum;
import com.gic.haoban.manage.api.service.CheckQywxSettingApiService;
import com.gic.haoban.manage.api.service.DealSyncOperationApiService;
import com.gic.haoban.manage.api.service.ExternalClerkRelatedApiService;
import com.gic.haoban.manage.api.service.WxEnterpriseApiService;
import com.gic.haoban.manage.service.config.Config;
import com.gic.haoban.manage.service.dao.mapper.*;
import com.gic.haoban.manage.service.entity.TabHaobanExternalClerkRelated;
import com.gic.haoban.manage.service.entity.TabHaobanWxEnterprise;
import com.gic.haoban.manage.service.entity.ext.MemberStaffRelExtDO;
import com.gic.haoban.manage.service.pojo.QywxTagSyncInfoPojo;
import com.gic.haoban.manage.service.service.ExternalClerkRelatedService;
import com.gic.haoban.manage.service.service.WxEnterpriseService;
import com.gic.haoban.manage.service.service.hm.WxUserAddLogService;
import com.gic.member.api.dto.MemberDTO;
import com.gic.member.api.dto.MemberSourceDetailDTO;
import com.gic.member.api.dto.MemberSourceShowDTO;
import com.gic.member.api.service.MemberApiService;
import com.gic.member.api.service.MemberEntranceApiService;
import com.gic.member.api.service.MemberService;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;
import com.gic.wechat.api.service.qywx.QywxUserApiService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
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.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ExternalClerkRelatedApiServiceImpl implements ExternalClerkRelatedApiService {

    private static final Logger log = LogManager.getLogger(ExternalClerkRelatedApiServiceImpl.class);

    @Autowired
    private TabHaobanExternalClerkRelatedMapper tabHaobanExternalClerkRelatedMapper;
    @Autowired
    private TabHaobanStaffClerkRelationMapper staffClerkRelationMapper;
    @Autowired
    private WxEnterpriseMapper wxEnterriseMapper;
    @Autowired
    private QywxUserApiService qywxUserApiService;
    @Autowired
    private Config config;
    @Autowired
    private ExternalUseridLogMapper externalUseridLogMapper;
    @Autowired
    private CheckQywxSettingApiService checkQywxSettingApiService;
    @Autowired
    private WxEnterpriseApiService wxEnterpriseApiService;
    @Autowired
    private MemberApiService memberApiService;
    @Autowired
    private WxUserAddLogService wxUserAddLogService;
    @Autowired
    private WxEnterpriseService wxEnterpriseService;
    @Autowired
    private DealSyncOperationApiService dealSyncOperationApiService;
    @Autowired
    private MemberEntranceApiService memberEntranceApiService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private ExternalClerkRelatedService externalClerkRelatedService;

    /**
     * 查询会员在企业下的好友关系
     *
     * @param memberId       : 会员id
     * @param wxEnterpriseId : 微信企业id
     * @param enterpriseId   : 企业id
     * @return : 返回会员导购关联关系
     */
    @Override
    public List<ExternalClerkRelatedDTO> listByMemberIdAndWxEnterpriseId(String memberId, String wxEnterpriseId, String enterpriseId) {
        List<TabHaobanExternalClerkRelated> list = tabHaobanExternalClerkRelatedMapper.listByMemberIdAndWxEnterpriseId(memberId, wxEnterpriseId, enterpriseId);
        return EntityUtil.changeEntityListByJSON(ExternalClerkRelatedDTO.class, list);
    }

    @Override
    public List<ExternalClerkRelatedDTO> listByMemberIdList(List<String> memberIdList, String wxEnterpriseId,
                                                            String enterpriseId) {
        List<ExternalClerkRelatedDTO> list = tabHaobanExternalClerkRelatedMapper.listByMemberIdList(memberIdList, wxEnterpriseId, enterpriseId);
        return list;
    }

    @Override
    public List<ExternalClerkRelatedDTO> listByWxEnterpriseIdAndWxUserId(String staffId, String wxEnterpriseId) {
        return EntityUtil.changeEntityListByJSON(ExternalClerkRelatedDTO.class, tabHaobanExternalClerkRelatedMapper.listByWxEnterpriseIdAndWxUserId(staffId, wxEnterpriseId));
    }

    @Override
    public List<ExternalClerkRelatedDTO> listByWxEnterpriseIdAndWxUserIds(List<String> staffIdList, String wxEnterpriseId) {
        if (CollectionUtils.isEmpty(staffIdList)) {
            return Collections.emptyList();
        }
        return EntityUtil.changeEntityListByJSON(ExternalClerkRelatedDTO.class, tabHaobanExternalClerkRelatedMapper.listByWxEnterpriseIdAndWxUserIds(staffIdList, wxEnterpriseId));
    }

    @Override
    public ExternalClerkRelatedDTO getExternalClerkByRelationKeyAndPre(String relationKey) {
        TabHaobanExternalClerkRelated related = tabHaobanExternalClerkRelatedMapper.getByRelationKey(relationKey,0);
        return EntityUtil.changeEntityNew(ExternalClerkRelatedDTO.class, related);
    }

    @Override
    public Page<ExternalClerkRelatedDTO> pageExternalClerk(String wxEnterpriseId, String staffId, List<Integer> statusFlags, BasePageInfo pageInfo) {
        PageHelper.startPage(pageInfo);
        List<TabHaobanExternalClerkRelated> ret = tabHaobanExternalClerkRelatedMapper.listByWxEnterpriseIdAndWxUserIdAndStatus(wxEnterpriseId, staffId, statusFlags);
        return PageUtil.changePageHelperToCurrentPage(new PageInfo<>(ret), ExternalClerkRelatedDTO.class);
    }

    @Override
    public boolean pushExternalByRelationKey(String relationKey) {
        tabHaobanExternalClerkRelatedMapper.pushExternalByRelationKey(relationKey);
        return true;
    }

    @Override
    public List<ExternalClerkRelatedDTO> listByEnterpriseIdAndDate(
            String enterpriseId, Date date) {
        List<TabHaobanExternalClerkRelated> list = tabHaobanExternalClerkRelatedMapper.listByEnterpriseIdAndDate(enterpriseId, date);
        return EntityUtil.changeEntityListByJSON(ExternalClerkRelatedDTO.class, list);
    }

    @Override
    public Page<ExternalClerkRelatedDTO> pageMemberUnionByParams(List<String> userIdList, List<String> sendMemberIds,
                                                                 String enterpriseId, BasePageInfo pageInfo) {
        PageHelper.startPage(pageInfo.getPageNum(), pageInfo.getPageSize());
        return PageUtil.changePageHelperToCurrentPage(tabHaobanExternalClerkRelatedMapper.pageMemberUnionByParams(userIdList, sendMemberIds, enterpriseId), ExternalClerkRelatedDTO.class);
    }

    @Override
    public ServiceResponse<ExternalClerkRelatedDTO> bindMemberIdExternalByRelationKey(String relationKey, String enterpriseId, String memberId, String unionid) {
        ServiceResponse<ExternalClerkRelatedDTO> resp = new ServiceResponse<>();
        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.getByRelationKey(relationKey,1);
        if (null == externalClerkRelated) {
            log.error("relationKey对应的关联关系不存在或删除：relationKey:{},memberId:{},unionid:{}", relationKey, memberId, unionid);
            resp.setCode(0);
            resp.setMessage("relationKey对应的关联关系不存在或删除");
            return resp;
        }
        if (!externalClerkRelated.getEnterpriseId().equals(enterpriseId)) {
            log.error("relationKey对应的企业与所传会员企业不对应：relationKey:{},memberId:{},unionid:{}", relationKey, memberId, unionid);
            resp.setCode(0);
            resp.setMessage("relationKey对应的企业与所传会员企业不对应");
            return resp;
        }
        updateExternalClerkRelated(enterpriseId, memberId, unionid, externalClerkRelated);

        resp.setResult(EntityUtil.changeEntityNew(ExternalClerkRelatedDTO.class, externalClerkRelated));
        return resp;
    }

    @Override
    public boolean bindMemberIdExternalById(String externalClerkRelatedId, String enterpriseId, String memberId, String unionid) {
        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.selectByPrimaryKey(externalClerkRelatedId);
        if (externalClerkRelated == null) {
            log.error("查询好办与gic数据为空,externalClerkRelatedId:{},enterpriseId:{},memberId:{},unionid:{}", externalClerkRelatedId, enterpriseId, memberId, unionid);
            return false;
        }
        updateExternalClerkRelated(enterpriseId, memberId, unionid, externalClerkRelated);
        return true;
    }

    /**
     * 更新好友关系
     *
     * @param enterpriseId
     * @param memberId
     * @param unionid
     * @param externalClerkRelated
     */
    private void updateExternalClerkRelated(String enterpriseId, String memberId, String unionid, TabHaobanExternalClerkRelated externalClerkRelated) {
        externalClerkRelated.setMemberId(memberId);
        externalClerkRelated.setUnionid(unionid);
        externalClerkRelated.setUpdateTime(new Date());
        externalClerkRelated.setStatusFlag(1);
        tabHaobanExternalClerkRelatedMapper.updateByPrimaryKeySelective(externalClerkRelated);

        String wxEnterpriseId = externalClerkRelated.getWxEnterpriseId();
        //同步标签
        pushTagSync(memberId, wxEnterpriseId, enterpriseId);
        //回调给会员，更新是否为企微好友
        log.info("通知会员 合并会员后更新为企微好友,memberId:{}", memberId);
        memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 1);
        //定制
        addDelFriendEvent(unionid, externalClerkRelated.getClerkId(), wxEnterpriseId, enterpriseId, memberId, externalClerkRelated.getStoreId(), 1);
        //日志
        wxUserAddLogService.updateMemberInfo(wxEnterpriseId, enterpriseId, externalClerkRelated.getStaffId(), externalClerkRelated.getExternalUserId(), memberId);
    }


    /**
     * 欧泊莱定制需求
     *
     * @param unionId
     * @param clerkId
     * @param enterpriseId
     * @param memberId
     * @param storeId
     */
    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());
            }
            msgBody.put("changeType", changeType);
            msgBody.put("addCreateTime", new Date());
            msgBody.put("delCreateTime", "");

            //获取渠道
            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 memberId
     * @param wxEnterpriseId
     * @param enterpriseId
     */
    private void pushTagSync(String memberId, String wxEnterpriseId, String enterpriseId) {
        QywxTagSyncInfoPojo pojo = new QywxTagSyncInfoPojo();
        pojo.setDataId(memberId);
        pojo.setTaskId("-1");
        pojo.setTaskType(QywxSyncTaskTypeEnum.MEMBER_SYNC.getType());
        //单个会员同步
        pojo.setSyncType(GicQywxSyncTypeEnum.SINGLE_WXENT_MEMNER_SYNC.getType());
        pojo.setWxEnterpriseId(wxEnterpriseId);
        pojo.setEnterpriseId(enterpriseId);
        GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
        try {
            clientInstance.sendMessage("qywxTagSyncDeal", JSONObject.toJSONString(pojo));
        } catch (Exception e) {
            log.info("异常：{}", e.getMessage(), e);
        }
    }

//    @Override
//    public ExternalClerkRelatedDTO getClerkFriendByUnionid(String enterpriseId, String clerkId, String unionid) {
//        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.getClerkExternalByUnionId(enterpriseId, clerkId, unionid);
//        ExternalClerkRelatedDTO clerkRelatedDTO = EntityUtil.changeEntityNew(ExternalClerkRelatedDTO.class, externalClerkRelated);
//        return clerkRelatedDTO;
//    }

    @Override
    public ExternalClerkRelatedDTO getExternalClerkByWxUserIdAncExternalUserId(String wxEnterpriseId, String staffId, String enterpriseId, String externalUserId) {
        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.getExternalClerkByWxUserIdAncExternalUserId(wxEnterpriseId, staffId, enterpriseId, externalUserId);
        if(null == externalClerkRelated) {
            externalClerkRelated = this.tabHaobanExternalClerkRelatedMapper.getExternalClerkByWxUserIdAncExternalUserIdSelf(wxEnterpriseId, staffId, enterpriseId, externalUserId) ;
        }
        return EntityUtil.changeEntityNew(ExternalClerkRelatedDTO.class, externalClerkRelated);
    }

    @Override
    public List<ExternalClerkRelatedDTO> listByIds(String wxEnterpriseId, List<String> ids) {
        List<TabHaobanExternalClerkRelated> list = tabHaobanExternalClerkRelatedMapper.listByIds(wxEnterpriseId, ids);
        return EntityUtil.changeEntityListNew(ExternalClerkRelatedDTO.class, list);
    }

    @Override
    public Page<String> pageExternalByEnterpriseId(String wxEnterpriseId, String enterpriseId, BasePageInfo pageInfo) {
        PageHelper.startPage(pageInfo);
        List<String> memberIDs = tabHaobanExternalClerkRelatedMapper.listMemberIdByEnterpriseId(wxEnterpriseId, enterpriseId);
        return PageUtil.changePageHelperToCurrentPage(new PageInfo<>(memberIDs));
    }

    @Override
    public Page<String> pageExternalByEnterpriseId(String wxEnterpriseId, String enterpriseId, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<String> memberIDs = tabHaobanExternalClerkRelatedMapper.listMemberIdByEnterpriseId(wxEnterpriseId, enterpriseId);
        return PageUtil.changePageHelperToCurrentPage(new PageInfo<>(memberIDs));
    }

    @Override
    public List<String> listExternalClerkMemberIdsByMemberIds(String wxEnterpriseId, List<String> memberIds) {
        return tabHaobanExternalClerkRelatedMapper.listMemberIdsByMemberIds(memberIds, wxEnterpriseId);
    }

    @Override
    public List<ExternalClerkRelatedShortInfoDTO> listExternalClerkByMemberId(String memberId, String enterpriseId) {
        if (StringUtils.isAnyBlank(memberId)) {
            return null;
        }
        List<TabHaobanExternalClerkRelated> list = tabHaobanExternalClerkRelatedMapper.listByMemberId(memberId, enterpriseId);
        return EntityUtil.changeEntityListNew(ExternalClerkRelatedShortInfoDTO.class, list);
    }

    @Override
    public List<ExternalClerkRelatedShortInfoDTO> listExternalClerkByMemberId(String memberId) {
        if (StringUtils.isBlank(memberId)) {
            return null;
        }
        List<TabHaobanExternalClerkRelated> list = tabHaobanExternalClerkRelatedMapper.listByMemberId(memberId, null);
        return EntityUtil.changeEntityListNew(ExternalClerkRelatedShortInfoDTO.class, list);
    }

    @Override
    public List<String> listStoreIdByMemberId(String memberId) {
        if (StringUtils.isBlank(memberId)) {
            return null;
        }
        return tabHaobanExternalClerkRelatedMapper.listStoreIdByMemberId(memberId , null);
    }

    @Override
    public List<String> listStoreIdByMemberId(String memberId, Date endTime) {
        if (StringUtils.isBlank(memberId)) {
            return null;
        }
        if(null == endTime) {
            return this.listStoreIdByMemberId(memberId) ;
        }
        String addCreateTime = String.valueOf(endTime.getTime()/1000) ;
        return tabHaobanExternalClerkRelatedMapper.listStoreIdByMemberId(memberId , addCreateTime);
    }

    @Override
    public void delByMemberIdAndEnterpriseId(String memberId, String enterpriseId, String mergeMemberId, int type) {
       // 0 删除会员 1合并会员 2会员换绑
       if(type==0) {
           log.info("删除会员,memberId：{}", memberId);
           this.tabHaobanExternalClerkRelatedMapper.updateStatusByMemberId(memberId, enterpriseId);
       }else if(type==1) {
           //合并会员,会员会先调删除,在调合并。顺序不能调换
           log.info("合并会员,memberId：{},新memberId={}", memberId , mergeMemberId);
           int i = tabHaobanExternalClerkRelatedMapper.countByMemberId(memberId, enterpriseId);
           if (i > 0) {
               tabHaobanExternalClerkRelatedMapper.updateMemberIdByMemberId(mergeMemberId, memberId, enterpriseId);
               log.info("会员合并 ,更新为企微好友,新memberId:{}", mergeMemberId);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, mergeMemberId, 1);
           }
       }else if(type==2) {
           int m1 = this.tabHaobanExternalClerkRelatedMapper.countByMemberId(memberId, enterpriseId) ;
           int m2 = this.tabHaobanExternalClerkRelatedMapper.countByMemberId(mergeMemberId, enterpriseId) ;
           log.info("合并换绑,m1={},好友数={}, m2={},好友数={}", memberId,m1,mergeMemberId,m2);
           if(m1==0 && m2==0) {
               log.info("都是非企微好友");
           }else if(m1==0 && m2>0) {
               this.tabHaobanExternalClerkRelatedMapper.updateMemberIdByMemberId(memberId, mergeMemberId, enterpriseId);
               log.info("会员换绑 ,更新为企微好友,新memberId:{}", memberId);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 1);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, mergeMemberId, 0);
           }else if(m1>0 && m2==0) {
               this.tabHaobanExternalClerkRelatedMapper.updateMemberIdByMemberId(mergeMemberId, memberId, enterpriseId);
               log.info("会员换绑 ,更新为企微好友,新memberId:{}", mergeMemberId);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, mergeMemberId, 1);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 0);
           }else if(m1>0 && m2>0) {
               List<String> m1IdList = this.tabHaobanExternalClerkRelatedMapper.getIdList(memberId, enterpriseId) ;
               List<String> m2IdList = this.tabHaobanExternalClerkRelatedMapper.getIdList(mergeMemberId, enterpriseId) ;
               this.tabHaobanExternalClerkRelatedMapper.updateMemberByIdList(mergeMemberId, m1IdList);
               this.tabHaobanExternalClerkRelatedMapper.updateMemberByIdList(memberId, m2IdList);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 1);
               this.memberApiService.updateMemberQywxFlag(enterpriseId, mergeMemberId, 1);
           }
       }
    }
    
    @Override
    public void delByMemberIdAndEnterpriseId(String memberId, String enterpriseId, String mergeMemberId) {
        log.info("删除会员或者合并会员,memberId:{},enterpriseId:{},mergeMemberId:{}", memberId, enterpriseId, mergeMemberId);
        if (StringUtils.isBlank(mergeMemberId)) {
            this.delByMemberIdAndEnterpriseId(memberId, enterpriseId, mergeMemberId, 0);
        } else {
            this.delByMemberIdAndEnterpriseId(memberId, enterpriseId, mergeMemberId, 1);
        }
    }


    @Override
    public boolean isFriends(String memberId, String clerkId, String enterpriseId) {
        StaffClerkRelationDTO staffClerkRelation = staffClerkRelationMapper.getOneByClerkId(clerkId,null);
        if (staffClerkRelation == null) {
            return false;
        }
        String staffId = staffClerkRelation.getStaffId();
        return this.isQwFriend(enterpriseId, staffId, memberId).getResult() ;
    }
    
    @Override
    public com.gic.api.base.commons.ServiceResponse<Boolean> isQwFriend(String enterpriseId, String staffId, String memberId) {
        log.info("查询是否好友enterpriseId={},staffId={},memberId={}",enterpriseId, staffId, memberId);
        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.getByMemberIdAndStaffId(staffId, enterpriseId, memberId);
        if (externalClerkRelated == null) {
            return com.gic.api.base.commons.ServiceResponse.success(Boolean.FALSE);
        }
        return com.gic.api.base.commons.ServiceResponse.success(externalClerkRelated.getStatusFlag() == 1);
    }

    /**
     * @param enterpriseId
     * @param clerkId
     * @param unionId
     * @return
     */
    @Override
    public com.gic.api.base.commons.ServiceResponse<Boolean> isQwFriendWithUnionId(String enterpriseId, String clerkId, String unionId) {
        StaffClerkRelationDTO staffClerkRelation = staffClerkRelationMapper.getOneByClerkId(clerkId,null);
        if (staffClerkRelation == null) {
            return com.gic.api.base.commons.ServiceResponse.success(Boolean.FALSE);
        }
        String staffId = staffClerkRelation.getStaffId();
        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.getByUnionIdAndStaffId(staffId, enterpriseId, unionId);
        if (externalClerkRelated == null) {
            return com.gic.api.base.commons.ServiceResponse.success(Boolean.FALSE);
        }
        return com.gic.api.base.commons.ServiceResponse.success(externalClerkRelated.getStatusFlag() == 1);
    }

    //    @Override
//    public com.gic.api.base.commons.ServiceResponse<String> getExternalUseridForWxa(String enterpriseId, String staffId,
//            String memberId) {
//        TabHaobanExternalClerkRelated externalClerkRelated = tabHaobanExternalClerkRelatedMapper.getByMemberIdAndStaffId(staffId, enterpriseId, memberId);
//        if(null != externalClerkRelated) {
//            return com.gic.api.base.commons.ServiceResponse.success(externalClerkRelated.getExternalClerkRelatedId());
//        }
//        return com.gic.api.base.commons.ServiceResponse.failure("9999", "无好友关系") ;
//    }
    
    @Override
    public List<String> listMemberAndStaff(List<String> memberIdList, String staffId, String enterpriseId) {
        List<String> list = tabHaobanExternalClerkRelatedMapper.listMemberAndStaff(memberIdList, staffId, enterpriseId);
        return list;
    }

    @Override
    public Map<String, List<ClerkStaffWxUserDTO>> listMemberStaffRel(List<String> memberIdList, List<String> clerkIdList, String enterpriseId, String wxEnterpriseId) {
        if (CollectionUtils.isEmpty(memberIdList) || CollectionUtils.isEmpty(clerkIdList)) {
            // 2个列表都为空查不了关系
            return Collections.emptyMap();
        }
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        if (qwDTO == null) {
            return Collections.emptyMap();
        }
        List<MemberStaffRelExtDO> res = staffClerkRelationMapper.listMemberStaffRelNew(memberIdList, clerkIdList, enterpriseId, wxEnterpriseId);
        if (CollectionUtils.isEmpty(res)) {
            return Collections.emptyMap();
        }
        return res.stream().collect(Collectors.toMap(
                // key-memberId
                MemberStaffRelExtDO::getMemberId,
                // value-list
                e -> new ArrayList<>(Collections.singletonList(new ClerkStaffWxUserDTO(e.getStaffId(), e.getStaffClerkId(), e.getMemberExternalUserId(),e.getAddFriendTime()))),
                // 重复key的value添加到集合
                (List<ClerkStaffWxUserDTO> oldList, List<ClerkStaffWxUserDTO> newList) -> {
                    oldList.addAll(newList);
                    return oldList;
                }));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResponse updateNewExternalUserid(String wxEnterpriseId) {
        log.info("企业外部联系人id start,wxEnterpriseId:{}", wxEnterpriseId);
        TabHaobanWxEnterprise tabHaobanWxEnterprise = wxEnterriseMapper.selectByPrimaryKey(wxEnterpriseId);
        ServiceResponse serviceResponse = new ServiceResponse();
        if (tabHaobanWxEnterprise == null) {
            log.info("企业外部联系人id为空");
            serviceResponse.setCode(HaoBanErrCodeCommon.ERR_0.getCode());
            serviceResponse.setMessage("企业外部联系人id为空");
            return serviceResponse;
        }
        String lockKey = "updateNewExternalUserid_" + wxEnterpriseId;
        if (RedisUtil.isLocked(lockKey)) {
            log.info("redis锁，lockKey：{}", lockKey);
            String corpName = tabHaobanWxEnterprise.getCorpName();
            serviceResponse.setCode(HaoBanErrCodeCommon.ERR_0.getCode());
            serviceResponse.setMessage(corpName + "已经在转换中，请勿重复操作！");
            return serviceResponse;
        }
        Integer externalFlag = tabHaobanWxEnterprise.getExternalFlag();
        if (externalFlag == 1 || externalFlag == 2) {
            log.info("已经在转换成功或转换中，请勿重复操作：wxEnterpriseId:{}", wxEnterpriseId);
            String corpName = tabHaobanWxEnterprise.getCorpName();
            serviceResponse.setCode(HaoBanErrCodeCommon.ERR_0.getCode());
            serviceResponse.setMessage(corpName + "已经在转换成功或转换中，请勿重复操作！");
            return serviceResponse;
        }
        RedisUtil.lock(lockKey, 1L, TimeUnit.DAYS, 0L);
        try {
            WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
            updateNewExUserId(tabHaobanWxEnterprise.getWxEnterpriseId(), qwDTO.getThirdCorpid());
            log.info("企业外部联系人id end,wxEnterpriseId:{}", wxEnterpriseId);
            RedisUtil.unlock(lockKey);
            serviceResponse.setCode(HaoBanErrCodeCommon.ERR_1.getCode());
            serviceResponse.setMessage(HaoBanErrCodeCommon.ERR_1.getMsg());
            return serviceResponse;
        } catch (Exception e) {
            log.info("企业外部联系人id异常,wxEnterpriseId:{},{}", wxEnterpriseId, e.getMessage(), e);
            RedisUtil.unlock(lockKey);
            serviceResponse.setCode(HaoBanErrCodeCommon.ERR_0.getCode());
            serviceResponse.setMessage("企业外部联系人id转换异常,请联系技术人员查看");
            return serviceResponse;
        }
    }

    @Override
    @Deprecated
    public void updateNewExternalUseridMq(String res) {
        log.info("更新新的外部联系人id mq,start");
    }

    @Override
    public List<ExternalClerkRelatedShortInfoDTO> listByMemberIdAndEnterpriseId(String memberId, String enterpriseId) {
        List<TabHaobanExternalClerkRelated> list = tabHaobanExternalClerkRelatedMapper.listByMemberId(memberId, enterpriseId);
        return EntityUtil.changeEntityListNew(ExternalClerkRelatedShortInfoDTO.class, list);
    }

    @Override
    public ExternalClerkRelatedDTO getByWxEnterpriseIdAndUnionId(String wxEnterpriseId, String staffId, String unionid) {
        TabHaobanExternalClerkRelated related = tabHaobanExternalClerkRelatedMapper.getByWxEnterpriseIdAndUnionId(wxEnterpriseId, staffId, unionid);
        return EntityUtil.changeEntityNew(ExternalClerkRelatedDTO.class, related);
    }

    @Override
    public FriendMemberStatusDTO getFriendMemberStatus(String memberId, String enterpriseId) {
        TabHaobanExternalClerkRelated tabHaobanExternalClerkRelated = tabHaobanExternalClerkRelatedMapper.getByEnterpriseIdAndMemberId(enterpriseId, memberId, null);
        if (tabHaobanExternalClerkRelated != null) {
            TabHaobanExternalClerkRelated hasFriend = tabHaobanExternalClerkRelatedMapper.getByEnterpriseIdAndMemberId(enterpriseId, memberId, 1);
            if (hasFriend != null) {
                FriendMemberStatusDTO friendMemberStatusDTO = new FriendMemberStatusDTO();
                friendMemberStatusDTO.setStatusFlag(1);
                friendMemberStatusDTO.setLastCreateTime(hasFriend.getCreateTime());
                return friendMemberStatusDTO;
            } else {
                TabHaobanExternalClerkRelated hasCancelFriend = tabHaobanExternalClerkRelatedMapper.getByEnterpriseIdAndMemberId(enterpriseId, memberId, 2);
                if (hasCancelFriend != null) {
                    FriendMemberStatusDTO friendMemberStatusDTO = new FriendMemberStatusDTO();
                    friendMemberStatusDTO.setStatusFlag(2);
                    friendMemberStatusDTO.setLastCancelCreateTime(hasCancelFriend.getCreateTime());
                    return friendMemberStatusDTO;
                }
            }
        }
        FriendMemberStatusDTO friendMemberStatusDTO = new FriendMemberStatusDTO();
        friendMemberStatusDTO.setStatusFlag(0);
        return friendMemberStatusDTO;
    }

    /**
     * 更新状态
     *
     * @param corpid
     * @param wxEnterpriseId
     */
    private void updateAgreeExternalUseridFlag(String corpid, String wxEnterpriseId) {
        //serviceCorpid 默认为：达摩网络
        boolean flag = qywxUserApiService.finishExternalUseridMigration(corpid, config.getCorpid());
        log.info("更新新的外部联系人id最后一页，设置迁移完成：flag:{}", flag);
        if (flag) {
            //成功
            wxEnterpriseApiService.agreeExternalUseridFlag(wxEnterpriseId, 1);
        } else {
            //失败
            wxEnterriseMapper.updateExternalFlagById(3, wxEnterpriseId);
            //回退老的
            //externalUseridLogMapper.updateOldExternalUserId(wxEnterpriseId);
            //更新状态为失败
            externalUseridLogMapper.updateStatusFlagByWxEnterpriseId(0, wxEnterpriseId);
        }
    }

    @Override
    public boolean isExternalFriendByMemberId(String memberId, String enterpriseId) {
        int count = tabHaobanExternalClerkRelatedMapper.countByMemberId(memberId, enterpriseId);
        return count > 0;
    }

    /**
     * 更新新的外部联系人id
     *
     * @param wxEnterpriseId wx企业标识
     * @param corpid         corpid
     * @author mozhu
     * @date 2021-12-13 15:40:30
     */
    private void updateNewExUserId(String wxEnterpriseId, String corpid) {
        wxEnterriseMapper.updateExternalFlagById(2, wxEnterpriseId);
        messageAlert(wxEnterpriseId, "更新新的外部联系人id");
        // 限流器
        RRateLimiter rateLimiter = RedisUtil.getRedisClient().getRateLimiter("haoban:manage3:updateNewExUserId:limit");
        // 每1秒产生5个令牌
        rateLimiter.trySetRate(RateType.OVERALL, 5, 1, RateIntervalUnit.SECONDS);
        int pageNum = 1;
        // 开启消息发送
        while (true) {
            // 获取令牌
            rateLimiter.acquire();
            //企微转换最多支持1000个
            PageInfo<TabHaobanExternalClerkRelated> tabHaobanWxEnterprisePageInfo = pageExternalByWxEnterpriseId(wxEnterpriseId, pageNum, 1000);
            List<TabHaobanExternalClerkRelated> enterprisePageInfoList = tabHaobanWxEnterprisePageInfo.getList();
            if (CollectionUtils.isEmpty(enterprisePageInfoList)) {
                if (pageNum == 1) {
                    log.info("如果没有好友，直接转换完成..corpid:{}", corpid);
                    updateAgreeExternalUseridFlag(corpid, wxEnterpriseId);
                }
                break;
            }
            pageNum++;
            List<String> externalUserIdList = enterprisePageInfoList.stream().map(TabHaobanExternalClerkRelated::getExternalUserId).collect(Collectors.toList());
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("corpid", corpid);
            jsonObject.put("wxEnterpriseId", wxEnterpriseId);
            jsonObject.put("externalUserIdList", externalUserIdList);
            jsonObject.put("externalUserId", externalUserIdList.get(0));
            //是否是最后一批
            if (tabHaobanWxEnterprisePageInfo.isIsLastPage()) {
                jsonObject.put("isLastPage", true);
            } else {
                jsonObject.put("isLastPage", false);
            }
            GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
            try {
                clientInstance.sendMessage("updateNewExUserIdMq", JSONObject.toJSONString(jsonObject));
            } catch (Exception e) {
                log.info("企微转换id发送消息队列异常：{}", e.getMessage(), e);
            }
        }
    }

    /**
     * 根据企业id分页
     *
     * @param wxEnterpriseId 企业标识
     * @param pageNum        页面num
     * @param pageSize       页面大小
     * @return {@link Page<ExternalClerkRelatedDTO> }
     * @author mozhu
     * @date 2021-12-13 15:10:19
     */
    private PageInfo<TabHaobanExternalClerkRelated> pageExternalByWxEnterpriseId(String wxEnterpriseId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<TabHaobanExternalClerkRelated> tabHaobanWxEnterpriseList = tabHaobanExternalClerkRelatedMapper.pageExternalByEnterpriseId(wxEnterpriseId);
        return new PageInfo<>(tabHaobanWxEnterpriseList);
    }


    /**
     * 消息提醒
     * 告警
     *
     * @param wxEnterpriseId wx企业标识
     * @param titleSub       子标题
     */
    private void messageAlert(String wxEnterpriseId, String titleSub) {
        ProviderLocalTag providerLocalTag = ProviderLocalTag.tag.get();
        String traceId = providerLocalTag.traceId;
        AlertMessageDTO messageDTO = new AlertMessageDTO();
        messageDTO.setTraceId(traceId);
        messageDTO.setWxEnterpriseId(wxEnterpriseId);
        messageDTO.setAlertTitle(titleSub);
        messageDTO.setAlertType(AlertTypeEnum.GET_NEW_EXTERNAL_USERID.getType());
        checkQywxSettingApiService.alertCallback(JSONObject.toJSONString(messageDTO));
    }


    @Override
    public int countFriendCountByClerkId(String wxEnterpriseId, String enterpriseId, String staffId, String clerkId) {
        return tabHaobanExternalClerkRelatedMapper.countByClerkId(wxEnterpriseId, enterpriseId, staffId, clerkId);
    }


    @Override
    public void initWxEnterpriseFriend(String wxEnterpriseId) {
        log.info("刷新整个企业的好友开始={}", wxEnterpriseId);
        String taskName = "刷新整个企微好友";
        String taskId = dealSyncOperationApiService.createWxFriendTaskSingle(wxEnterpriseId, taskName, "-1", "管理员", SyncTaskTypeEnum.FRIEND_WX_ENTEPRISE.getType());
        if (StringUtils.isNotBlank(taskId)) {
            List<String> staffList = staffClerkRelationMapper.listByWxEnterpriseId(wxEnterpriseId);
            if (CollectionUtils.isEmpty(staffList)) {
                log.info("没有要刷新的：{},{}", wxEnterpriseId, staffList);
                return;
            }
            staffList = staffList.stream().distinct().collect(Collectors.toList());
            log.info("刷新好友,关联导购的staff数={}",staffList.size());
            for (String staffId : staffList) {
                this.dealSyncOperationApiService.dealWxFriendClerkSingle(taskId, staffId, staffId, wxEnterpriseId);
            }
        }
    }

    @Override
    public int getCountExternalClerk(String wxEnterpriseId, String staffId, List<Integer> statusFlags) {
        return tabHaobanExternalClerkRelatedMapper.getCountExternalClerk(wxEnterpriseId,staffId,statusFlags);
    }
    
    @Override
    public int updateExternalStatus(String wxEnterpriseId, String externalUserid,int status) {
        return this.tabHaobanExternalClerkRelatedMapper.updateExternalStatus(wxEnterpriseId,externalUserid,status);
    }

    @Override
    public com.gic.api.base.commons.ServiceResponse<String> getMemberIdByExternalId(String wxEnterpriseId, String externalUserId) {
        return com.gic.api.base.commons.ServiceResponse.success(externalClerkRelatedService.getMemberIdByExternalId(wxEnterpriseId,externalUserId));
    }
}
