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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
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.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.JSONObject;
import com.gic.api.base.commons.ServiceResponse;
import com.gic.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.EntityUtil;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.common.utils.DingUtils;
import com.gic.haoban.manage.api.dto.StaffClerkRelationDTO;
import com.gic.haoban.manage.api.dto.WxEnterpriseDTO;
import com.gic.haoban.manage.api.dto.WxEnterpriseQwDTO;
import com.gic.haoban.manage.api.dto.hm.HmLinkChatDTO;
import com.gic.haoban.manage.api.dto.hm.HmLinkDTO;
import com.gic.haoban.manage.api.dto.hm.HmLinkStoreDTO;
import com.gic.haoban.manage.api.dto.hm.HmLinkStoreSettingDTO;
import com.gic.haoban.manage.api.dto.hm.HmLinkWxaDTO;
import com.gic.haoban.manage.api.dto.hm.HmPageDTO;
import com.gic.haoban.manage.api.enums.hm.HmLinkTypeEnum;
import com.gic.haoban.manage.api.service.hm.HmLinkApiService;
import com.gic.haoban.manage.service.config.Config;
import com.gic.haoban.manage.service.dao.mapper.TabHaobanExternalClerkRelatedMapper;
import com.gic.haoban.manage.service.dao.mapper.TabHaobanStaffClerkRelationMapper;
import com.gic.haoban.manage.service.entity.TabHaobanExternalClerkRelated;
import com.gic.haoban.manage.service.entity.TabHaobanStaff;
import com.gic.haoban.manage.service.errorcode.HaoBanErrCode;
import com.gic.haoban.manage.service.pojo.bo.chat.GroupChatHmBO;
import com.gic.haoban.manage.service.pojo.bo.hm.HmLinkBO;
import com.gic.haoban.manage.service.pojo.bo.hm.HmPageBO;
import com.gic.haoban.manage.service.pojo.bo.hm.HmQrcodeBO;
import com.gic.haoban.manage.service.pojo.bo.hm.KeyDataLinkBO;
import com.gic.haoban.manage.service.pojo.qo.HmQrcodeTempQO;
import com.gic.haoban.manage.service.service.KeyDataService;
import com.gic.haoban.manage.service.service.MemberQueryService;
import com.gic.haoban.manage.service.service.StaffService;
import com.gic.haoban.manage.service.service.WxEnterpriseService;
import com.gic.haoban.manage.service.service.chat.GroupChatHmService;
import com.gic.haoban.manage.service.service.hm.HmLinkChatService;
import com.gic.haoban.manage.service.service.hm.HmLinkService;
import com.gic.haoban.manage.service.service.hm.HmLinkStoreService;
import com.gic.haoban.manage.service.service.hm.HmPageService;
import com.gic.haoban.manage.service.service.hm.HmQrcodeService;
import com.gic.haoban.manage.service.service.hm.HmQrcodeTempService;
import com.gic.member.api.dto.es.MemberDataDTO;
import com.gic.member.api.dto.es.MemberStoreClerkDataDTO;
import com.gic.member.api.service.MemberService;
import com.gic.member.tag.api.dto.MemberExistDTO;
import com.gic.member.tag.api.service.MemberTagGroupApiService;
import com.gic.redis.data.util.RedisUtil;
import com.gic.search.engine.api.constant.OperateEnum;
import com.gic.search.engine.api.dto.ESResponseQueryBatch;
import com.gic.search.engine.api.dto.dynamic.DynamicSearchDTO;
import com.gic.search.engine.api.filter.NewNodeAddUtil;
import com.gic.search.engine.api.service.dynamic.ESDataDynamicOperationApiService;
import com.gic.wechat.api.dto.qywx.welcome.QywxExternalcontactDTO;
import com.gic.wechat.api.dto.qywx.welcome.QywxExternalcontactResultDTO;
import com.gic.wechat.api.service.qywx.QywxUserApiService;

@Service("hmLinkApiService")
public class HmLinkApiServiceImpl implements HmLinkApiService {

    private static org.apache.logging.log4j.Logger log = LogManager.getLogger(HmLinkApiService.class);

    @Autowired
    private HmLinkService hmLinkService;
    @Autowired
    private HmLinkStoreService hmLinkStoreService;
    @Autowired
    private KeyDataService keyDataService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private MemberQueryService memberQueryService;
    @Autowired
    private HmQrcodeService hmQrcodeService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private QywxUserApiService qywxUserApiService;
    @Autowired
    private Config config;
    @Autowired
    private WxEnterpriseService wxEnterpriseService;
    @Autowired
    private HmQrcodeTempService hmQrcodeTempService;
    @Autowired
    private TabHaobanExternalClerkRelatedMapper tabHaobanExternalClerkRelatedMapper;
    @Autowired
    private HmPageService hmPageService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private StaffService staffService;
    @Autowired
    private HmLinkChatService hmLinkChatService;
    @Autowired
    private ESDataDynamicOperationApiService esDataDynamicOperationApiService;
    @Autowired
    private MemberTagGroupApiService memberTagGroupApiService;
    @Autowired
    private GroupChatHmService groupChatHmService;
    @Autowired
    private TabHaobanStaffClerkRelationMapper staffClerkRelationMapper;

    @Override
    public ServiceResponse<String> getHmLinkUrl() {
        return ServiceResponse.success(config.getHmLinkUrl());
    }

    @Override
    public ServiceResponse<HmLinkDTO> getByLinkId(String wxEnterpriseId, String enterpriseId, Long linkId) {
        HmLinkBO link = this.hmLinkService.getByLinkId(wxEnterpriseId, enterpriseId, linkId);
        if (null != link) {
            HmLinkDTO dto = EntityUtil.changeEntityByJSON(HmLinkDTO.class, link);
            if (dto.getLinkType() == HmLinkTypeEnum.HM_LINK_TYPE_1.getLinkType()
                    || dto.getLinkType() == HmLinkTypeEnum.HM_LINK_TYPE_2.getLinkType()) {
                List<HmLinkStoreDTO> storeList = this.hmLinkStoreService.listByLinkId(dto.getWxEnterpriseId(),
                        dto.getEnterpriseId(), linkId);
                dto.setStoreList(storeList);
            }
            if (dto.getLinkType() == HmLinkTypeEnum.CHAT_HM_LINK_TYPE.getLinkType()) {
                List<HmLinkChatDTO> linkChatList = this.hmLinkChatService.listByLinkId(dto.getWxEnterpriseId(),
                        dto.getEnterpriseId(), linkId);
                dto.setLinkChatList(linkChatList);
            }
            return ServiceResponse.success(dto);
        }
        return ServiceResponse.failure(HaoBanErrCode.ERR_OTHER.getCode(), "链接不存在");
    }

    @Override
    public ServiceResponse<HmLinkDTO> getByShortCode(String shortCode) {
        HmLinkBO bo = this.hmLinkService.getByLinkShortCode(shortCode);
        if (null == bo) {
            return ServiceResponse.failure(HaoBanErrCode.ERR_OTHER.getCode(), "链接不存在");
        }
        HmLinkDTO dto = EntityUtil.changeEntityByJSON(HmLinkDTO.class, bo);
        return ServiceResponse.success(dto);
    }

    @Override
    public ServiceResponse<List<HmLinkDTO>> listForSms(String wxEnterpriseId, String enterprieId, String linkName,
            Integer linkType) {
        return this.listForSms(wxEnterpriseId, enterprieId, linkName, linkType, null);
    }

    @Override
    public ServiceResponse<List<HmLinkDTO>> listForSms(String wxEnterpriseId, String enterprieId, String linkName,
            Integer linkType, List<String> creatorIdList) {
        List<HmLinkBO> list = this.hmLinkService.listForSms(wxEnterpriseId, enterprieId, linkName, linkType,
                creatorIdList);
        List<HmLinkDTO> retList = EntityUtil.changeEntityListByJSON(HmLinkDTO.class, list);
        return ServiceResponse.success(retList);
    }

    @Override
    public ServiceResponse<String> save(HmLinkDTO dto) {
        String id = this.hmLinkService.saveLink(dto, dto.getStoreList());
        return ServiceResponse.success(id);
    }

    // 群链接
    private ServiceResponse<HmLinkWxaDTO> getLinkChatHmFromWxa(String wxEnterpriseId, String enterpriseId,
            String mixPhone, String unionid, String memberId, HmLinkBO link, HmLinkWxaDTO retDTO) {
        Long hmId = link.getOtherChatHmId();
        Long linkId = link.getLinkId();
        List<HmLinkChatDTO> hmList = this.hmLinkChatService.listByLinkId(wxEnterpriseId, enterpriseId, linkId);
        if (StringUtils.isNotEmpty(mixPhone)) {
            String mobile = this.keyDataService.getMobile(mixPhone, link.getShortCode());
            log.info("查询手机号,mobile={},mixPhone={}", mobile, mixPhone);
            String mobileMemberId = this.memberService.getMemberIdByPhoneNumber(mobile, enterpriseId);
            if (StringUtils.isNotBlank(mobileMemberId)) {
                memberId = mobileMemberId;
            }
        }
        if (CollectionUtils.isNotEmpty(hmList)) {
            for (HmLinkChatDTO item : hmList) {
                boolean flag = this.memberCondition(enterpriseId, memberId, item, link.getCreatorId(),
                        link.getUpdateTime());
                if (flag) {
                    log.info("使用特殊群活码={}", item.getChatHmId());
                    hmId = item.getChatHmId();
                    break;
                }
            }
        }
        GroupChatHmBO hm = null;
        if (null == hmId) {
            log.info("群活码不存在");
            return ServiceResponse.failure("9999", "群活码不存在");
        }
        hm = this.groupChatHmService.getById(hmId);
        if (null == hm) {
            log.info("群活码不存在,hmid={}", hmId);
        }
        retDTO.setHmQrcode(hm.getWxQrCode());
        return ServiceResponse.success(retDTO);
    }

    @Override
    public ServiceResponse<HmLinkWxaDTO> getLinkHmFromWxa(String enterpriseId, Integer whitchStore, String inStoreId,
            String inClerkId, String linkShortCode, String mixPhone, String unionid, String memberId) {
        if ("-1".equals(memberId)) {
            memberId = null;
        }
        HmQrcodeBO hm = null;
        HmLinkWxaDTO retDTO = new HmLinkWxaDTO();
        log.info("小程序获取活码={},linkShortCode={},mixPhone={},memberId={},unionid={},门店={}{}", enterpriseId, linkShortCode,
                mixPhone, memberId, unionid, inStoreId, whitchStore);
        HmLinkBO link = this.hmLinkService.getByLinkShortCodeCache(linkShortCode);
        Map<String, String> remarkMap = new HashMap<>();
        if (null == link) {
            log.error("链接记录不存,linkShortCode={}", linkShortCode);
            return ServiceResponse.failure(HaoBanErrCode.ERR_OTHER.getCode(), "无效的链接");
        }
        // 查询页面
        retDTO.setPageId(link.getPageId());
        // 查询页面
        HmPageBO page = this.hmPageService.queryHmPageDetail(link.getPageId());
        if (null != page) {
            retDTO.setPage(EntityUtil.changeEntityByJSON(HmPageDTO.class, page));
        }
        Long linkId = link.getLinkId();
        String wxEnterpriseId = link.getWxEnterpriseId();
        retDTO.setWxEnterpriseId(wxEnterpriseId);
        retDTO.setEnterpriseId(enterpriseId);
        WxEnterpriseDTO wxEnterpriseDTO = wxEnterpriseService.selectById(wxEnterpriseId);
        if (wxEnterpriseDTO == null) {
            log.error("未查询到微信企业,id={}", wxEnterpriseId);
            return ServiceResponse.failure(HaoBanErrCode.ERR_OTHER.getCode(), "未查到微信企业");
        }

        // 如果是社群链接
        if (link.getLinkType() == HmLinkTypeEnum.CHAT_HM_LINK_TYPE.getLinkType()) {
            log.info("群链接,linkId={}", link.getLinkId());
            return this.getLinkChatHmFromWxa(wxEnterpriseId, enterpriseId, mixPhone, unionid, memberId, link, retDTO);
        }

        // 判断导购是否有活码,如果没有返回错误
        if (StringUtils.isNotBlank(inClerkId)) {
            hm = this.getHmFromClerk(inClerkId, wxEnterpriseId, memberId, enterpriseId);
            if (null == hm) {
                remarkMap.put("reason", "无任何导购活码");
                retDTO.setRemarkMap(remarkMap);
                return ServiceResponse.success(retDTO);
            }
        }
        // 直接返回门店的导购活码,如果没有返回错误
        if (null == hm && StringUtils.isNotBlank(inStoreId)) {
            String customRuleJson = link.getCustomRuleJson();
            log.info("选门店后,whitchStore={},自定义规则={}", whitchStore, customRuleJson);
            JSONObject storeRuleObj = JSONObject.parseObject(customRuleJson);
            int openFlag = storeRuleObj.getIntValue("open");
            // whitchStore 1推荐门店 2附件门店 3省市区门店
            if (null == whitchStore) {
                whitchStore = 1;
            }
            if (openFlag == 1) {
                int dz = 0, dy = 0;
                // 1推荐门店 2附件门店 3省市区门店
                int storeType = storeRuleObj.getIntValue("store_type");
                // 省市区
                if (whitchStore == 3) {
                    HmLinkStoreSettingDTO cityStore = storeRuleObj.getObject("city_store", HmLinkStoreSettingDTO.class);
                    dz = cityStore.getDz();
                    dy = cityStore.getDy();
                } else if (whitchStore == 1 || whitchStore == 2) {
                    HmLinkStoreSettingDTO store = storeRuleObj.getObject("store", HmLinkStoreSettingDTO.class);
                    if (whitchStore == 2 || (storeType == 1 && whitchStore == 1)) {
                        // 附近门店 或者 推荐门店
                        dz = store.getDz();
                        dy = store.getDy();
                    } else if (storeType == 2 && whitchStore == 1) {
                        // 附近门店的推荐门店
                        dz = store.getNdz();
                        dy = store.getNdy();
                    }
                }
                hm = this.getHmFormStore(wxEnterpriseId, inStoreId, dz, dy, new ArrayList<>(), enterpriseId, memberId);
                log.info("获取到的门店配置dz={},dy={},获取的活码={}", dz, dy, JSON.toJSONString(hm));
                if (null == hm) {
                    remarkMap.put("reason", "无任何导购活码");
                    retDTO.setRemarkMap(remarkMap);
                    return ServiceResponse.success(retDTO);
                }
                remarkMap.put("sm", "会员选门店活码");
            }
        }
        String mobile = null;
        if (StringUtils.isNotEmpty(mixPhone)) {
            mobile = this.keyDataService.getMobile(mixPhone, linkShortCode);
            log.info("查询手机号,mobile={},mixPhone={}", mobile, mixPhone);
            String mobileMemberId = this.memberService.getMemberIdByPhoneNumber(mobile, enterpriseId);
            if (StringUtils.isNotBlank(mobileMemberId)) {
                memberId = mobileMemberId;
            }
        }
        // 会员门店
        if (null == hm) {
            HmLinkStoreSettingDTO fwStore = null;
            HmLinkStoreSettingDTO xgStore = null;
            if (StringUtils.isNotBlank(link.getStoreRuleJson())) {
                String storeRuleJson = link.getStoreRuleJson();
                log.info("会员门店规则={}", storeRuleJson);
                JSONObject storeRuleObj = JSONObject.parseObject(storeRuleJson);
                fwStore = storeRuleObj.getObject("fw_store", HmLinkStoreSettingDTO.class);
                if (null == fwStore || fwStore.getOpen() == 0) {
                    fwStore = null;
                }
                xgStore = storeRuleObj.getObject("xg_store", HmLinkStoreSettingDTO.class);
                if (null == xgStore || xgStore.getOpen() == 0) {
                    xgStore = null;
                }
                log.info("小程序获取活码memberId={}", memberId);
                if (StringUtils.isNotBlank(memberId)) {
                    MemberDataDTO member = this.getMemberClerk(enterpriseId, memberId);
                    String mainClerkId = member.getMainClerkId();
                    String mainStoreId = member.getMainStoreId();
                    // 服务门店
                    if (null != fwStore) {
                        log.info("处理服务门店逻辑");
                        List<String> clerkIdList = new ArrayList<>();
                        if (StringUtils.isNotBlank(mainClerkId)) {
                            clerkIdList.add(mainClerkId);
                            if (fwStore.getZs() == 1) {
                                hm = this.getHmFromClerk(mainClerkId, wxEnterpriseId, memberId, enterpriseId);
                                if (null != hm) {
                                    log.info("获取服务导购活码,mainClerkId={}", mainClerkId);
                                    remarkMap.put("sm", "主门店-服务导购");
                                }
                            }
                        }
                        if (null == hm && StringUtils.isNotBlank(mainStoreId)) {
                            hm = this.getHmFormStore(wxEnterpriseId, mainStoreId, fwStore.getDz(), fwStore.getDy(),
                                    clerkIdList, enterpriseId, memberId);
                            if (null != hm) {
                                remarkMap.put("sm", "主门店-店长-店员");
                            }
                        }
                    }
                    // 协管门店
                    List<MemberStoreClerkDataDTO> list = member.getStoreClerkRel();
                    if (null == hm && null != xgStore && CollectionUtils.isNotEmpty(list)) {
                        log.info("处理协管门店逻辑");
                        // 排序协管导购
                        list = this.sortMemberClerk(enterpriseId, memberId, list);
                        List<String> storeIdList = new ArrayList<>();
                        // 协管导购
                        List<String> clerkIdList = new ArrayList<>();
                        for (MemberStoreClerkDataDTO item : list) {
                            String clerkId = item.getClerkIdRel();
                            if (mainStoreId.equals(item.getStoreIdRel())) {
                                log.info("协管逻辑,主门店直接过滤");
                                continue;
                            }
                            if (xgStore.getZs() == 1) {
                                hm = this.getHmFromClerk(clerkId, wxEnterpriseId, memberId, enterpriseId);
                                if (null != hm) {
                                    remarkMap.put("sm", "协管活码-主导购");
                                    storeIdList = null;
                                    break;
                                }
                            }
                            storeIdList.add(item.getStoreIdRel());
                            clerkIdList.add(clerkId);
                        }
                        // 店长
                        if (null == hm && xgStore.getDz() == 1 && CollectionUtils.isNotEmpty(storeIdList)) {
                            for (String storeId : storeIdList) {
                                hm = this.getHmFormStore(wxEnterpriseId, storeId, 1, 0, clerkIdList, enterpriseId,
                                        memberId);
                                if (null != hm) {
                                    remarkMap.put("sm", "协管活码-店长");
                                    break;
                                }
                            }
                        }
                        // 店员
                        if (null == hm && xgStore.getDy() == 1 && CollectionUtils.isNotEmpty(storeIdList)) {
                            for (String storeId : storeIdList) {
                                hm = this.getHmFormStore(wxEnterpriseId, storeId, 0, 1, clerkIdList, enterpriseId,
                                        memberId);
                                if (null != hm) {
                                    remarkMap.put("sm", "协管活码-店员");
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        if (null == hm && StringUtils.isNotBlank(link.getCustomRuleJson())) {
            String customRuleJson = link.getCustomRuleJson();
            log.info("自定义规则={}", customRuleJson);
            JSONObject storeRuleObj = JSONObject.parseObject(customRuleJson);
            int openFlag = storeRuleObj.getIntValue("open");
            if (openFlag == 1) {
                // 门店规则1推荐门店 2附件门店
                int storeType = storeRuleObj.getIntValue("store_type");
                // 活码的门店
                List<HmLinkStoreDTO> storeList = this.hmLinkStoreService.listByLinkId(wxEnterpriseId, enterpriseId,
                        linkId);
                storeList = this.setStoreAddress(wxEnterpriseId, enterpriseId, storeList);
                log.info("门店规则={},推荐门店列表={}", storeType, JSON.toJSONString(storeList));
                HmLinkStoreSettingDTO cityStore = storeRuleObj.getObject("city_store", HmLinkStoreSettingDTO.class);
                // 是否开启省市区门店查询
                int selectStoreFlag = cityStore.getOpen();
                log.info("省市区开启={}", selectStoreFlag);
                retDTO.setStoreType(storeType);

                retDTO.setStoreList(storeList);
                retDTO.setSelectStoreFlag(selectStoreFlag);
            }
        }
        if (null != hm) {
            log.info("获取到单人活码={}", JSON.toJSONString(hm));
            retDTO.setHmId(hm.getHmId());
            remarkMap.put("clerk", hm.getClerkId());
            // 判断是否已经是好友
            boolean isFriend = false;
            if (null != memberId) {
                String staffId = hm.getStaffId();
                TabHaobanExternalClerkRelated friend = tabHaobanExternalClerkRelatedMapper
                        .getByMemberIdAndStaffId(staffId, enterpriseId, memberId);
                if (null != friend) {
                    isFriend = true;
                    log.info("已经是好友,staffid={},memberId={}", staffId, memberId);
                    retDTO.setHmQrcode(hm.getWxQrcode());
                    remarkMap.put("sm", "老好友,取单人活码");
                }
            }

            if (!isFriend) {
                KeyDataLinkBO bo = new KeyDataLinkBO();
                bo.setUnionid(unionid);
                bo.setLinkId(linkId);
                bo.setHmId(hm.getHmId());
                if (StringUtils.isNotBlank(mixPhone) && StringUtils.isNotBlank(mobile)) {
                    bo.setMobile(mobile);
                }
                String dthmKey = this.keyDataService.saveDataForLink(enterpriseId, bo);
                remarkMap.put("dthmKey", dthmKey);
                if (null != dthmKey) {
                    WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
                    ServiceResponse<String> addResp = this.addQrcode(hm, dthmKey, qwDTO, retDTO);
                    if (!addResp.isSuccess()) {
                        remarkMap.put("sm", "创建动态活码失败,取单人活码");
                        if (StringUtils.isBlank(hm.getWxQrcode())) {
                            remarkMap.put("reason", "无任何导购活码");
                            retDTO.setRemarkMap(remarkMap);
                            return ServiceResponse.success(retDTO);
                        }
                        retDTO.setHmQrcode(hm.getWxQrcode());
                    } else {
                        remarkMap.put("动态", "是");
                        retDTO.setHmQrcode(addResp.getResult());
                    }
                }
            }
        }
        // 生成动态活码
        retDTO.setRemarkMap(remarkMap);
        log.info("活码数据返回={}", JSON.toJSONString(retDTO));
        return ServiceResponse.success(retDTO);
    }

    private List<HmLinkStoreDTO> setStoreAddress(String wxEnterpriseId, String enterpriseId,
            List<HmLinkStoreDTO> storeList) {
        if (CollectionUtils.isNotEmpty(storeList)) {
            // 过滤到达上线的门店
            List<String> okStoreIdList = this.hmQrcodeService.getHmStoreForWxa(wxEnterpriseId, enterpriseId);
            log.info("storeId={}", okStoreIdList);
            storeList = storeList.stream().filter(dto -> okStoreIdList.contains(dto.getStoreId()))
                    .collect(Collectors.toList());
            List<String> storeIdList = storeList.stream().map(dto -> dto.getStoreId()).collect(Collectors.toList());
            String[] storeIds = new String[storeIdList.size()];
            for (int i = 0; i < storeIdList.size(); i++) {
                storeIds[i] = storeIdList.get(i);
            }
            List<StoreDTO> dtoList = this.storeService.getStores(storeIds);
            Map<String, StoreDTO> map = dtoList.stream()
                    .collect(Collectors.toMap(StoreDTO::getStoreId, dto -> dto, (k1, k2) -> k1));
            storeList = storeList.stream().filter(o->null != map.get(o.getStoreId())  && map.get(o.getStoreId()).getStatus()==2)
                            .collect(Collectors.toList());
            storeList.forEach(item -> {
                if (null != map.get(item.getStoreId())) {
                    item.setStoreAddress(map.get(item.getStoreId()).getStoreAddress());
                }
            });
        }
        return storeList;
    }

    // 先不排序,可以随机
    private List<MemberStoreClerkDataDTO> sortMemberClerk(String enterpriseId, String memberId,
            List<MemberStoreClerkDataDTO> list) {
        return list;
    }

    // 创建活码
    private ServiceResponse<String> addQrcode(HmQrcodeBO hm, String key, WxEnterpriseQwDTO qwDTO, HmLinkWxaDTO retDTO) {
        String limitQrcode = this.limitIp(hm);
        if (StringUtils.isNotEmpty(limitQrcode)) {
            return ServiceResponse.failure(HaoBanErrCode.ERR_OTHER.getCode(), "超限制数");
        }
        QywxExternalcontactDTO paramsDTO = new QywxExternalcontactDTO();
        // 联系方式类型,1-单人, 2-多人 场景，1-在小程序中联系，2-通过二维码联系
        paramsDTO.setType(1);
        paramsDTO.setScene(2);
        paramsDTO.setRemark(hm.getName());
        paramsDTO.setSkipVerify(hm.getPassFlag() == 1);
        paramsDTO.setState("DT" + key);
        TabHaobanStaff tabHaobanStaff = staffService.selectById(hm.getStaffId());
        if(null == tabHaobanStaff) {
            return ServiceResponse.failure("9999", "成员不存在") ;
        }
        if (tabHaobanStaff != null) {
            if (qwDTO.needOpenUserId3th()) {
                paramsDTO.setUser(Arrays.asList(tabHaobanStaff.getWxOpenUseId()));
            } else {
                paramsDTO.setUser(Arrays.asList(tabHaobanStaff.getWxUserId()));
            }
        }
        QywxExternalcontactResultDTO wxResp = qywxUserApiService.addContactWay(qwDTO.getThirdCorpid(), qwDTO.getSelf3thSecret(), paramsDTO , qwDTO.isSelf(),qwDTO.getUrlHost());
        log.info("创建动态活码参数corpid={},app={},param={},返回={}", qwDTO.getThirdCorpid(), config.getWxSuiteid(),
                JSON.toJSONString(paramsDTO), JSON.toJSONString(wxResp));
        if (null != wxResp && 0 == wxResp.getErrcode()) {
            retDTO.setHmQrcode(wxResp.getQr_code());
            HmQrcodeTempQO qo = new HmQrcodeTempQO();
            qo.setWxEnterpriseId(hm.getWxEnterpriseId());
            qo.setWxConfigId(wxResp.getConfig_id());
            qo.setWxQrcode(wxResp.getQr_code());
            qo.setRelationId(key);
            qo.setCorpid(qwDTO.getThirdCorpid());
            this.hmQrcodeTempService.save(qo);
            return ServiceResponse.success(wxResp.getQr_code());
        }
        return ServiceResponse.failure(HaoBanErrCode.ERR_OTHER.getCode(), "企微错误：" + wxResp.getErrmsg());
    }

    private String limitIp(HmQrcodeBO hm) {
        String ipKey = "hmadd:limit:ip";
        int ipLimitCount = 300;
        RRateLimiter rateLimiter = RedisUtil.getRedisClient().getRateLimiter(ipKey);
        rateLimiter.trySetRate(RateType.OVERALL, ipLimitCount, 1, RateIntervalUnit.SECONDS);
        if (rateLimiter.tryAcquire()) {
            return null;
        }
        String msg = "活码调用次数告警【ip】";
        DingUtils.send(msg, false);
        return hm.getWxQrcode();
    }

    private HmQrcodeBO getHmFromClerk(String clerkId, String wxEnterpriseId, String memberId, String enterpriseId) {
        if (StringUtils.isBlank(clerkId) || "-1".equals(clerkId)) {
            return null;
        }
        HmQrcodeBO hm = this.hmQrcodeService.queryByClerkId(clerkId, wxEnterpriseId, 1);
        // 已经达上线
        if (null != hm && hm.getOverFlag() == 1 && StringUtils.isNotBlank(memberId)) {
            String staffId = hm.getStaffId();
            TabHaobanExternalClerkRelated friend = tabHaobanExternalClerkRelatedMapper.getByMemberIdAndStaffId(staffId,
                    enterpriseId, memberId);
            if (null != friend) {
                return hm;
            } else {
                return null;
            }
        }
        return hm;
    }

    private HmQrcodeBO getHmFormStore(String wxEnterpriseId, String inStoreId, int dz, int dy, List<String> clerkIdList,
            String enterpriseId, String memberId) {
        if (StringUtils.isBlank(inStoreId) || "-1".equals(inStoreId)) {
            return null;
        }
        HmQrcodeBO hm = null;
        ClerkDTO dzClerk = this.clerkService.getClerkLeaderByStoreId(inStoreId);
        if (null != dzClerk) {
            clerkIdList.add(dzClerk.getClerkId());
            if (dz == 1) {
                hm = this.getHmFromClerk(dzClerk.getClerkId(), wxEnterpriseId, memberId, enterpriseId);
                if (null != hm) {
                    log.info("获取到店长活码,clerkId={},inStoreId={}", hm.getClerkId(), inStoreId);
                }
            }
        } else {
            log.info("店长不存在,storeId={}", inStoreId);
        }
        // 店员需要过滤主导购、店长
        log.info("过滤的导购={}", clerkIdList);
        if (null == hm && dy == 1) {
            List<HmQrcodeBO> list = this.hmQrcodeService.listByStoreId(wxEnterpriseId, inStoreId, 0, 1);
            if (CollectionUtils.isNotEmpty(list)) {
                log.info("查询门店下有活码的导购数={}", list.size());
                list = list.stream().filter(dto -> !clerkIdList.contains(dto.getClerkId()))
                        .collect(Collectors.toList());
            }
            if (CollectionUtils.isNotEmpty(list)) {
                log.info("门店下{},导购数={}", inStoreId, list.size());
                hm = list.get(new Random().nextInt(list.size()));
                if (null != hm) {
                    log.info("获取到店员活码,clerkId={},inStoreId={}", hm.getClerkId(), inStoreId);
                }
            }
        }
        return hm;
    }

    // 冗余会员信息
    private MemberDataDTO getMemberClerk(String enterpriseId, String memberId) {
        String returnFields = "memberId,mainClerkId,mainStoreId,storeClerkRel";
        JSONObject memberObj = this.memberQueryService.queryDataSingle(enterpriseId, memberId, returnFields);
        if (null == memberObj) {
            return null;
        }
        log.info("会员信息={}", memberObj.toJSONString());
        MemberDataDTO memberDataDTO = memberObj.toJavaObject(MemberDataDTO.class);
        return memberDataDTO;
    }

    private boolean memberCondition(String enterpriseId, String memberId, HmLinkChatDTO dto, String creatorId,
            Date updateTime) {
        boolean flag = true;
        int memberType = dto.getMemberType();
        String limitCondition = dto.getFilterJson();
        // 可见人群
        if (0 == memberType) {
            JSONObject search = JSON.parseObject(limitCondition);
            search = NewNodeAddUtil.addNewNodeForAnd("memberId", OperateEnum.OPERATE_CONTAIN.getValue(), memberId,
                    search);
            search = this.storeService.parseSelectData(search, enterpriseId, creatorId, updateTime, null, null, null);
            search.put("id", memberId);
            DynamicSearchDTO searchDTO = new DynamicSearchDTO();
            searchDTO.setEnterpriseId(enterpriseId);
            searchDTO.setColumnCategoryCode("member");
            searchDTO.setSearchJson(search);
            log.info("人群查询条件为：" + JSON.toJSONString(searchDTO));
            ESResponseQueryBatch esRes = this.esDataDynamicOperationApiService.queryDataBatch(searchDTO, false, null);
            List<JSONObject> list = esRes.getRes();
            log.info("人群查询结果为：" + list.size());
            return list.size() > 0;
        }
        // 会员分组
        if (1 == memberType) {
            String[] arr = limitCondition.split(",");
            List<String> memberLabelIds = new ArrayList<>();
            for (int i = 0; i < arr.length; i++) {
                if (StringUtils.isNotBlank(arr[i])) {
                    memberLabelIds.add(arr[i]);
                }
            }
            MemberExistDTO memberExistDTO = new MemberExistDTO();
            memberExistDTO.setMemberId(memberId);
            memberExistDTO.setEnterpriseId(enterpriseId);
            memberExistDTO.setMemberTagGroupIds(memberLabelIds);
            flag = this.memberTagGroupApiService.memberIsExistGroup(memberExistDTO);
            log.info("分组-limitCondition={},mid={},返回={}", limitCondition, memberId, flag);
        }
        return flag;
    }
    
    public ServiceResponse<HmLinkWxaDTO> getMemberClerkHm(String enterpriseId , String memberId , String unionid , Long linkId) {
        log.info("getMemberClerkHm={},linkId={}",memberId,linkId);
        HmLinkWxaDTO retDTO = new HmLinkWxaDTO();
        HmQrcodeBO hm = null ;
        MemberDataDTO member = this.getMemberClerk(enterpriseId, memberId);
        List<MemberStoreClerkDataDTO> list = member.getStoreClerkRel();
        List<String> clerkIdList = list.stream().map(dto->dto.getClerkIdRel()).collect(Collectors.toList()) ;
        if(CollectionUtils.isEmpty(clerkIdList)) {
            log.info("会员下无导购");
            return ServiceResponse.failure("9999", "会员下无导购") ; 
        }
        HmLinkBO link = this.hmLinkService.getByLinkId(null, enterpriseId, linkId);
        if(null == link) {
            log.info("链接不存在,linkId={}",linkId);
            return ServiceResponse.failure("9999", "链接不存在") ; 
        }
        String wxEnterpriseId = link.getWxEnterpriseId() ;
        log.info("wxEnterpriseId={}",wxEnterpriseId);
        List<StaffClerkRelationDTO> staffClerkList = this.staffClerkRelationMapper.listByClerkIds(clerkIdList,wxEnterpriseId) ;
        if(CollectionUtils.isEmpty(staffClerkList)) {
            log.info("会员导购无关联成员");
            return ServiceResponse.failure("9999", "会员导购无关联成员") ; 
        }
        clerkIdList = staffClerkList.stream().map(dto->dto.getClerkId()).collect(Collectors.toList()) ;
        String mainClerkId = member.getMainClerkId();
        if(StringUtils.isNotBlank(mainClerkId)) {
            clerkIdList.add(mainClerkId);
        }
        List<String> friendClerkList = this.tabHaobanExternalClerkRelatedMapper.listFriendClerk(memberId,clerkIdList) ;
        if(CollectionUtils.isNotEmpty(friendClerkList)) {
            log.info("已存在好友");
        }else {
            friendClerkList = new ArrayList<>() ;
        }
        String mainStoreId = member.getMainStoreId();
        // 服务门店
        log.info("memberId={},主导购={}",memberId,mainClerkId);
        if (StringUtils.isNotBlank(mainClerkId)) {
            if(friendClerkList.contains(mainClerkId)) {
                hm = this.hmQrcodeService.queryByClerkId(mainClerkId, wxEnterpriseId, 1);
                if(null != hm) {
                    retDTO.setHmId(hm.getHmId());
                    retDTO.setHmQrcode(hm.getWxQrcode());
                    retDTO.setQwFriendFlag(1);
                    return ServiceResponse.success(retDTO);
                }
            }
            hm = this.getHmFromClerk(mainClerkId, wxEnterpriseId, memberId, enterpriseId);
            if (null != hm) {
                log.info("获取服务导购活码,mainClerkId={}", mainClerkId);
            }
        }
        // 协管门店
        if (null == hm &&  CollectionUtils.isNotEmpty(list)) {
            log.info("处理协管导购");
            // 协管导购
            for (MemberStoreClerkDataDTO item : list) {
                String clerkId = item.getClerkIdRel();
                if (StringUtils.isNotBlank(mainStoreId) && mainStoreId.equals(item.getStoreIdRel())) {
                    continue;
                }
                if(friendClerkList.contains(clerkId)) {
                    hm = this.hmQrcodeService.queryByClerkId(clerkId, wxEnterpriseId, 1);
                    if(null != hm) {
                        retDTO.setHmId(hm.getHmId());
                        retDTO.setHmQrcode(hm.getWxQrcode());
                        retDTO.setQwFriendFlag(1);
                        return ServiceResponse.success(retDTO);
                    }
                }
                hm = this.getHmFromClerk(clerkId, wxEnterpriseId, memberId, enterpriseId);
                if (null != hm) {
                    log.info("获取导购活码,clerkId={}", clerkId);
                    break ;
                }
            }
        }
        if (null != hm) {
            log.info("获取到单人活码={}", JSON.toJSONString(hm));
            retDTO.setHmId(hm.getHmId());
            KeyDataLinkBO bo = new KeyDataLinkBO();
            bo.setUnionid(unionid);
            bo.setHmId(hm.getHmId());
            // bo.setLinkId(hm.getHmId());
            String dthmKey = this.keyDataService.saveDataForLink(enterpriseId, bo);
            if (null != dthmKey) {
                WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
                if(null == qwDTO) {
                    log.info("wxEnterprise不存在={}",wxEnterpriseId);
                    return ServiceResponse.failure("9999", "企业不存在") ; 
                }
                ServiceResponse<String> addResp = this.addQrcode(hm, dthmKey, qwDTO, retDTO);
                if (!addResp.isSuccess()) {
                    if (StringUtils.isBlank(hm.getWxQrcode())) {
                        return ServiceResponse.success(retDTO);
                    }
                    retDTO.setHmQrcode(hm.getWxQrcode());
                } else {
                    retDTO.setHmQrcode(addResp.getResult());
                }
            }
        }
        // 生成动态活码
        log.info("活码数据返回={}", JSON.toJSONString(retDTO));
        return ServiceResponse.success(retDTO);
    }
}
