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


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.GICMQClientUtil;
import com.gic.commons.util.UniqueIdUtils;
import com.gic.dubbo.entity.ProviderLocalTag;
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.common.utils.EntityUtil;
import com.gic.haoban.common.utils.StringUtil;
import com.gic.haoban.manage.api.dto.ExternalClerkRelatedDTO;
import com.gic.haoban.manage.api.dto.MemberUnionidRelatedDTO;
import com.gic.haoban.manage.api.dto.SecretSettingDTO;
import com.gic.haoban.manage.api.dto.WxEnterpriseQwDTO;
import com.gic.haoban.manage.api.dto.qdto.hm.WxUserAddLogQDTO;
import com.gic.haoban.manage.api.enums.SecretTypeEnum;
import com.gic.haoban.manage.service.config.Config;
import com.gic.haoban.manage.service.dao.mapper.*;
import com.gic.haoban.manage.service.entity.*;
import com.gic.haoban.manage.service.service.ExternalClerkRelatedService;
import com.gic.haoban.manage.service.service.SecretSettingService;
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.search.engine.api.dto.ESResponseQuerySingle;
import com.gic.search.engine.api.dto.dynamic.DynamicSearchDTO;
import com.gic.search.engine.api.service.dynamic.ESDataDynamicOperationApiService;
import com.gic.wechat.api.dto.qywx.QywxNewExternalUseridDTO;
import com.gic.wechat.api.service.qywx.QywxUserApiService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static org.slf4j.LoggerFactory.getLogger;

@Service
public class ExternalClerkRelatedServiceImpl implements ExternalClerkRelatedService {

    private static final Logger logger = getLogger(ExternalClerkRelatedServiceImpl.class);

    @Autowired
    private TabHaobanExternalClerkRelatedMapper mapper;
    @Autowired
    private ESDataDynamicOperationApiService esDataDynamicOperationApiService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private MemberApiService memberApiService;
    @Autowired
    private WxUserAddLogService wxUserAddLogService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private MemberEntranceApiService memberEntranceApiService;
    @Autowired
    private Config config;
    @Autowired
    private WxEnterpriseService wxEnterpriseService;
    @Autowired
    private MemberUnionidRelatedMapper memberUnionidRelatedMapper;
    @Autowired
    private QywxUserApiService qywxUserApiService;
    @Autowired
    private TabHaobanRepairExternalUserMapper tabHaobanRepairExternalUserMapper;
    @Autowired
    private SecretSettingService secretSettingService;

    @Override
    public void insert(TabHaobanExternalClerkRelated related) {
        String clerkId = related.getClerkId();
        String externalUserId = related.getExternalUserId();
        TabHaobanExternalClerkRelated tab = mapper.selectByClerkIdAndExternalUserId(clerkId, externalUserId);
        if (tab == null) {
            String uuId = StringUtil.randomUUID();
            related.setStatusFlag(related.getStatusFlag() != null ? related.getStatusFlag() : 1);
            related.setExternalClerkRelatedId(uuId);
            related.setCreateTime(new Date());
            related.setUpdateTime(new Date());
            mapper.insertSelective(related);
        }
    }

    @Override
    public void delByUserIdAndExternalUserId(MemberUnionidRelatedDTO dto) {
        String staffId = dto.getStaffId();
        String externalUserid = dto.getExternalUserid();
        int count = mapper.delByUserIdAndExternalUserId(externalUserid,staffId);
        if (count <= 0) {
            logger.error("无需删除的好友数据：{}", JSON.toJSONString(dto));
            return;
        }
        String wxEnterpriseId = dto.getWxEnterpriseId() ;
        List<TabHaobanExternalClerkRelated> deleteRelatedList = mapper.listByExTernalUseridAndWxUserId(externalUserid, staffId, 2);
        if (CollectionUtils.isEmpty(deleteRelatedList)) {
            logger.info("无解除的好友关系：externalUserid:{},staffId:{}", externalUserid,staffId);
            return;
        }
        TabHaobanExternalClerkRelated related = deleteRelatedList.get(0);
        String enterpriseId = related.getEnterpriseId() ;
        //该企微该会员所有关联关系解除后通知会员
        List<TabHaobanExternalClerkRelated> list = mapper.listByExternalUseridAndWxEnterpriseId(dto.getExternalUserid(), wxEnterpriseId, Arrays.asList("1", "3", "4"));
        if (CollectionUtils.isEmpty(list)) {
            //删除的好友关系
            List<TabHaobanExternalClerkRelated> haobanExternalClerkRelatedList = mapper.listByExternalUseridAndWxEnterpriseId(dto.getExternalUserid(), wxEnterpriseId, Collections.singletonList("2"));
            for (TabHaobanExternalClerkRelated externalClerkRelated : haobanExternalClerkRelatedList) {
                String memberId = externalClerkRelated.getMemberId();
                logger.info("通知会员 删除会员后更新为非企微好友 memberId:{}", memberId);
                memberApiService.updateMemberQywxFlag(enterpriseId, memberId, 0);
                memberApiService.updateMemberQywxEveryOccasion(enterpriseId, memberId, 0, new Date());
            }
        } else {
            //删除后 每次回调会员
            for (TabHaobanExternalClerkRelated externalClerkRelated : deleteRelatedList) {
                String memberId = externalClerkRelated.getMemberId();
                logger.info("通知会员 删除会员后更新为非企微好友时间 memberId:{}", memberId);
                memberApiService.updateMemberQywxEveryOccasion(enterpriseId, memberId, 1, new Date());
            }
        }
        //添加日志
        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());
        wxUserAddLogService.save(wxUserAddLogQDTO);
        //定制
        addDelFriendEvent(related.getUnionid(), related.getClerkId(), wxEnterpriseId, enterpriseId, related.getMemberId(), related.getStoreId(), 0);
    }

    /**
     * 欧泊莱定制需求
     *
     * @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)) {
            logger.info("非定制，无需广播通知");
            return;
        }

        if (StringUtils.isBlank(memberId)) {
            logger.info("会员不存在:{}", memberId);
            return;
        }
        logger.info("欧泊莱定制：推送会员,memberId:{},changeType:{}", memberId, changeType);
        //欧泊莱定制需求
        ClerkDTO clerkDTO = clerkService.getClerkByClerkId(clerkId);
        StoreDTO storeDTO = storeService.getStore(storeId);
        MemberDTO member = memberService.getMember(memberId);
        if (member == null) {
            logger.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);
            if (changeType == 0) {
                msgBody.put("delUserContact", 0);
                msgBody.put("delCreateTime", new Date());
            } else {
                msgBody.put("addCreateTime", "");
            }
            //获取渠道
            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) {
            logger.info("加好友事件订阅通知：{}", e.getMessage(), e);
        }
    }

    @Override
    public void delByUserIdAndExternalUserIdBatch(String wxEnterpriseId, String staffId, List<String> externalUserids) {
        mapper.delByUserIdAndExternalUserIdBatch(staffId, wxEnterpriseId, externalUserids);
    }

    @Override
    public void delByStoreIdAndStaffId(String storeId, String staffId) {
        mapper.delByStoreIdAndStaffId(storeId, staffId);
    }

    @Override
    public void delByStoreIds(Collection<String> storeIds) {
        mapper.delByStoreIds(storeIds);
    }

    @Override
    public void cleanStaffRelated(String wxEnterpriseId, List<String> staffIds) {
        if (staffIds != null && !staffIds.isEmpty()) {
            mapper.cleanStaffRelated(wxEnterpriseId, staffIds);
        }
    }

    @Override
    public void update(TabHaobanExternalClerkRelated exsitDTO) {
        exsitDTO.setUpdateTime(new Date());
        mapper.updateByPrimaryKeySelective(exsitDTO);

    }

    @Override
    public List<TabHaobanExternalClerkRelated> listByExternalUseridAndWxUserId(String externalUserid, String staffId) {
        return mapper.listByExTernalUseridAndWxUserId(externalUserid, staffId, 1);
    }

    @Override
    public List<TabHaobanExternalClerkRelated> listByExTernalUseridAndWxUserIdAllStatus(String wxEnterpriseId, String externalUserid, String staffId) {
        return mapper.listByExTernalUseridAndWxUserIdAllStatus(wxEnterpriseId, externalUserid, staffId);
    }

    @Override
    public ExternalClerkRelatedDTO getByMemberId(String staffId, String memberId) {
        return EntityUtil.changeEntityByJSON(ExternalClerkRelatedDTO.class, mapper.getByMemberId(staffId, memberId));
    }

    @Override
    public List<TabHaobanExternalClerkRelated> listExternalByUnionId(String enterpriseId, String unionId) {
        return mapper.listExternalByUnionId(enterpriseId, unionId);
    }

    @Override
    public List<TabHaobanExternalClerkRelated> listExternalByExternalUserid(String wxEnterpriseId, String externalUserid) {
        return mapper.listByExternalUserId(wxEnterpriseId, externalUserid);
    }

    @Override
    public String checkAndUpdateMemberByUnonId(String enterpriseId, String memberId, String unionId) {
        String returnFields = "id";
        try {
            JSONObject searchJson = new JSONObject();
            searchJson.put("id", memberId);
            DynamicSearchDTO search = new DynamicSearchDTO();
            search.setSearchJson(searchJson);
            search.setEnterpriseId(enterpriseId);
            search.setColumnCategoryCode("member");
            if (StringUtils.isNotBlank(returnFields)) {
                search.setReturnFileds(returnFields);
            }
            ESResponseQuerySingle single = esDataDynamicOperationApiService.queryDataSingle(search);
            JSONObject res = single.getRes();
            logger.info("返回数据：{}", JSONObject.toJSONString(res));
            if (res != null && res.size() > 0) {
                return memberId;
            }
            MemberDTO memberDTO = memberService.getMemberByUnionid(unionId, enterpriseId);
            if (null == memberDTO || memberDTO.getMemberId() == null) {
                logger.info("会员不存在：{}", unionId);
                return null;
            }
            //更新会员id
            mapper.updateMemberIdByMemberId(memberDTO.getMemberId(), memberId, enterpriseId);
            return memberDTO.getMemberId();
        } catch (Exception e) {
            logger.info("从搜索引擎中搜索会员数据异常, memberId : {}", memberId);
        }
        return null;
    }

    @Override
    public void repairExternalUserId(String wxEnterpriseIds) {
        logger.info("外部联系人检查,wxEnterpriseIds={}", wxEnterpriseIds);
        DingUtils.send("外部联系人修复消息,企业=" + wxEnterpriseIds + ",tranceid=" + ProviderLocalTag.tag.get().traceId, false);
        if (StringUtils.isEmpty(wxEnterpriseIds)) {
            return;
        }
        Object cache = RedisUtil.getCache("repairExternalUserId");
        String[] arr = wxEnterpriseIds.split(",");
        for (int i = 0; i < arr.length; i++) {
            String wxEnterpriseId = arr[i];
            if (StringUtils.isEmpty(wxEnterpriseId)) {
                continue;
            }
            int type = 0 ;
            if(wxEnterpriseId.endsWith("_")) {
                wxEnterpriseId = wxEnterpriseId.substring(0,wxEnterpriseId.length()-1) ;
                type = 1 ;
            }
            WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
            if (null == qwDTO) {
                logger.info("外部联系人检查,企业不存在,wxEnterpriseId={}", wxEnterpriseId);
                continue;
            }
            SecretSettingDTO secret = this.secretSettingService.getSecretSetting(wxEnterpriseId, SecretTypeEnum.CUSTOMIZED_APP.getVal());
            int pageSize = 800;
            int pageNum = 0;
            while (true) {
                List<TabHaobanExternalClerkRelated> list = this.mapper.listPageByWxenterpriseId(wxEnterpriseId, pageNum * pageSize, pageSize,type);
                if (CollectionUtils.isEmpty(list)) {
                    logger.info("{}完成",wxEnterpriseId);
                    break;
                }
                pageNum++;
                Set<String> externalUserIdSet = list.stream().map(dto -> dto.getExternalUserId()).collect(Collectors.toSet());
                Map<String,Date> dateMap = list.stream().collect(Collectors.toMap(TabHaobanExternalClerkRelated::getExternalUserId, TabHaobanExternalClerkRelated::getCreateTime,(k1,k2)->k1)) ;
                List<String> externalUserIdList = new ArrayList<>();
                externalUserIdList.addAll(externalUserIdSet);
                List<MemberUnionidRelated> unionidlist = this.memberUnionidRelatedMapper.listByWxEnterpriseIdAndExternalUserId(wxEnterpriseId, externalUserIdList);
                Map<String, String> map = unionidlist.stream().filter(dto -> StringUtils.isNotBlank(dto.getExternalUserid()) && StringUtils.isNotBlank(dto.getSelfExternalUserid()))
                        .collect(Collectors.toMap(MemberUnionidRelated::getExternalUserid, MemberUnionidRelated::getSelfExternalUserid, (k1, k2) -> k1));
                logger.info("外部联系人检查,第{}次,好友数={},unionid表数={},{}", pageNum, externalUserIdList.size(), unionidlist.size(),wxEnterpriseId);
                List<String> delList = new ArrayList<>();
                Set<String> checkSet = unionidlist.stream().map(dto -> dto.getExternalUserid()).collect(Collectors.toSet());
                List<String> checkList = new ArrayList<>();
                checkList.addAll(checkSet);
                for (String item : externalUserIdList) {
                    if (!checkList.contains(item)) {
                        delList.add(item);
                    }
                }
                logger.info("外部联系人检查,unionid表不存在记录的数量={},待检查数={}", delList.size(), checkList.size());
                List<String> notExistQwList = new ArrayList<>();
                List<TabHaobanRepairExternalUser> errorList = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(checkList)) {
                    List<String> qwList = new ArrayList<>();
                    List<QywxNewExternalUseridDTO> newExternalUseridList = null;
                    if (null != cache) {
                        newExternalUseridList = this.qywxUserApiService.getNewExternalUseridByList(qwDTO.getThirdCorpid(), config.getWxSuiteid(), checkList);
                    } else {
                        newExternalUseridList = this.qywxUserApiService.getSelfNewExternalUseridByList(qwDTO.getDkCorpid(), secret.getSecretVal(), checkList);
                    }
                    if (null != newExternalUseridList) {
                        logger.info("外部联系人检查,查询企微数={},返回数={}", checkList.size(), newExternalUseridList.size());
                        for (QywxNewExternalUseridDTO qywxNewExternalUseridDTO : newExternalUseridList) {
                            String new_external_userid = qywxNewExternalUseridDTO.getNew_external_userid();
                            String external_userid = qywxNewExternalUseridDTO.getExternal_userid();
                            qwList.add(external_userid);
                            if (new_external_userid.equals(external_userid)) {
                                continue;
                            } else {
                                logger.info("外部联系人检查,数据异常={}", new_external_userid, external_userid);
                                TabHaobanRepairExternalUser user = new TabHaobanRepairExternalUser();
                                user.setId(UniqueIdUtils.uniqueLong());
                                user.setUserId(external_userid);
                                user.setWxEnterpriseId(wxEnterpriseId);
                                user.setStatusFlag(111);
                                user.setRemark(new_external_userid);
                                if(null != dateMap.get(external_userid)) {
                                    user.setUpdateTime(dateMap.get(external_userid));
                                }
                                errorList.add(user);
                            }
                        }
                        if (checkList.size() != newExternalUseridList.size()) {
                            for (String item : checkList) {
                                if (!qwList.contains(item)) {
                                    notExistQwList.add(item);
                                }
                            }
                        }
                    } else {
                        logger.info("外部联系人检查,调用企业异常");
                    }
                    // 通过外部联系人查询不到
                    if (CollectionUtils.isNotEmpty(notExistQwList)) {
                        // 需要用自建的查询的
                        List<String> selfList = new ArrayList<>();
                        List<TabHaobanRepairExternalUser> addList = new ArrayList<>();
                        for (String item : notExistQwList) {
                            TabHaobanRepairExternalUser user = new TabHaobanRepairExternalUser();
                            user.setId(UniqueIdUtils.uniqueLong());
                            user.setUserId(item);
                            if (StringUtils.isNotBlank(map.get(item)) && !map.get(item).equals(item)) {
                                selfList.add(map.get(item));
                            }
                            user.setSelfUserId(map.get(item));
                            user.setWxEnterpriseId(wxEnterpriseId);
                            user.setStatusFlag(11);
                            user.setRemark("外部联系人ID错误");
                            if(StringUtils.isBlank(user.getSelfUserId())) {
                                user.setStatusFlag(12);
                                user.setRemark("unionid表记录存在,但代开联系人id NULL");
                            }
                            if(null != dateMap.get(item)) {
                                user.setUpdateTime(dateMap.get(item));
                            }
                            addList.add(user);
                        }

                        if (CollectionUtils.isNotEmpty(selfList)) {
                            newExternalUseridList = null;
                            if (null != cache) {
                                newExternalUseridList = this.qywxUserApiService.getNewExternalUseridByList(qwDTO.getThirdCorpid(), config.getWxSuiteid(), selfList);
                            } else {
                                newExternalUseridList = this.qywxUserApiService.getSelfNewExternalUseridByList(qwDTO.getDkCorpid(), secret.getSecretVal(), selfList);
                            }
                            Map<String, String> selfMap = new HashMap<>();
                            if (null != newExternalUseridList) {
                                selfMap = newExternalUseridList.stream().collect(Collectors.toMap(QywxNewExternalUseridDTO::getExternal_userid, QywxNewExternalUseridDTO::getNew_external_userid, (k1, k2) -> k1));
                            }
                            for (TabHaobanRepairExternalUser item : addList) {
                                item.setNewUserId(selfMap.get(item.getSelfUserId()));
                            }
                        }
                        this.tabHaobanRepairExternalUserMapper.batchInsert(addList);
                    }
                    // unionid表不存在的记录
                    if (CollectionUtils.isNotEmpty(delList)) {
                        List<TabHaobanRepairExternalUser> addList = new ArrayList<>();
                        for (String item : delList) {
                            TabHaobanRepairExternalUser user = new TabHaobanRepairExternalUser();
                            user.setId(UniqueIdUtils.uniqueLong());
                            user.setUserId(item);
                            user.setWxEnterpriseId(wxEnterpriseId);
                            user.setStatusFlag(1);
                            user.setRemark("无unionid表记录");
                            if(null != dateMap.get(item)) {
                                user.setUpdateTime(dateMap.get(item));
                            }
                            addList.add(user);
                        }
                        this.tabHaobanRepairExternalUserMapper.batchInsert(addList);
                    }

                    // 错误的ID
                    if (CollectionUtils.isNotEmpty(errorList)) {
                        this.tabHaobanRepairExternalUserMapper.batchInsert(errorList);
                    }
                }
            }
        }
    }

    @Override
    public List<String> getByStoreIdAndStaffId(String storeId, String staffId) {
        return mapper.getByStoreIdAndStaffId(storeId, staffId);
    }

    @Override
    public int getCountByMemberId(String memberId) {
        return mapper.getCountByMemberId(memberId);
    }
    
    @Override
    public void updateClerkInfo(String staffId, String oldClerkId, String newClerkId) {
        ClerkDTO clerk = this.clerkService.getclerkById(newClerkId);
        this.mapper.updateClerkInfo(staffId,oldClerkId , newClerkId , clerk.getStoreId());
    }
}
