package com.gic.haoban.manage.service.task.friend;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.haoban.manage.api.dto.*;
import com.gic.haoban.manage.api.enums.PreDealStatusEnum;
import com.gic.haoban.manage.api.enums.PreDealTypeEnum;
import com.gic.haoban.manage.api.enums.SyncTaskStatusEnum;
import com.gic.haoban.manage.api.service.ClerkMainStoreRelatedApiService;
import com.gic.haoban.manage.api.service.MemberUnionidRelatedApiService;
import com.gic.haoban.manage.service.entity.TabHaobanPreDealLog;
import com.gic.haoban.manage.service.entity.TabHaobanWxEnterpriseRelated;
import com.gic.haoban.manage.service.exception.WxApiLimitException;
import com.gic.haoban.manage.service.service.*;
import com.gic.haoban.manage.service.task.BaseSyncOperation;
import com.gic.member.api.dto.MemberSimpleDetailDTO;
import com.gic.member.api.dto.QywxMemberQDTO;
import com.gic.member.api.service.MemberEntranceApiService;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 导购和客户好友关系
 */
@Service
public class FriendSyncNewOperation implements BaseSyncOperation {

    private static final Logger logger = LoggerFactory.getLogger(FriendSyncNewOperation.class);
    @Autowired
    private PreDealService preDealService;
    @Autowired
    private MemberUnionidRelatedApiService memberUnionidRelatedApiService;
    @Autowired
    private SyncTaskService syncTaskService;
    @Autowired
    private ClerkMainStoreRelatedApiService clerkMainStoreRelatedApiService;
    @Autowired
    private StaffClerkRelationService staffClerkRelationService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private FriendClerkSyncNewOperation friendClerkSyncNewOperation;
    @Autowired
    private WxEnterpriseRelatedService wxEnterpriseRelatedService;
    @Autowired
    private MemberEntranceApiService memberEntranceApiService;

    private static final String TRY_AGAIN = "haoban_fresh_wx_friend_again_";

    @Override
    public void dealSingleByMq(DealParamMqDTO dealParamMqDTO, TabHaobanPreDealLog dataPre) {
        logger.info("同步好友开始,第三方={}", JSONObject.toJSONString(dataPre));
        String reason = "成功";
        boolean dealFlag = true;
        String relationKey = "-1";
        try {
            String wxEnterpriseId = dataPre.getWxEnterpriseId();
            String wxUserId =  dataPre.getDataId().split("###")[1] ;
            String taskId = dealParamMqDTO.getTaskId();
            String externalUserId = dataPre.getDataContent();
            String staffId = dataPre.getpDataId() ;

            if (dataPre.getStatusFlag() != PreDealStatusEnum.pre.getVal()) {
                logger.info("已经处理过，无需重复处理:{}", JSONObject.toJSONString(dataPre));
                return;
            }

            ExternalUserDTO externalUserDTO = memberUnionidRelatedApiService.getExternalUseridInfo(wxEnterpriseId, wxUserId, externalUserId);
            if (externalUserDTO == null) {
                dealFlag = false;
                reason = "好友不存在";
                return;
            }
            //relationkey
            relationKey = SecureUtil.md5(staffId + "_" + externalUserDTO.getName() + "_" + externalUserDTO.getAddCreateTime());
            logger.info("第三方生成relationKey：{},{},{} 客户={}, 结果={}",staffId,externalUserDTO.getName(),externalUserDTO.getAddCreateTime() , externalUserDTO.getExternalUserId() , relationKey);
            // 根据关联键relationkey查看自建应用 是否有数据
            TabHaobanPreDealLog selfPre = preDealService.getByRelationKey(taskId, PreDealTypeEnum.self_friend.getVal(), relationKey);
            if (null == selfPre) {
                logger.info("用户的自建应用不存在该数据：{},{}", JSONObject.toJSONString(dataPre), JSONObject.toJSONString(externalUserDTO));
                dealFlag = false;
                reason = "用户的自建应用不存在该数据：" + relationKey;
                return;
            }
            ExternalUserDTO selfUserData = JSON.parseObject(selfPre.getDataContent(), ExternalUserDTO.class);
            externalUserDTO.setUnionId(selfUserData.getUnionId());
            externalUserDTO.setSelfExternalUserId(selfUserData.getExternalUserId());
            externalUserDTO.setAvatar(selfUserData.getAvatar());
            externalUserDTO.setName(selfUserData.getName());
            //序列化数据
            String ret = dealMerge(externalUserDTO, dataPre);
            if (StringUtils.isNotBlank(ret)) {
                logger.info("好友创建失败：{},{}", ret, JSONObject.toJSONString(externalUserDTO));
                dealFlag = false;
                reason = ret + ":" + relationKey;
                return;
            }

            //更新状态
            preDealService.updateFriendStatusByDataId(taskId, dataPre.getDataId(), PreDealStatusEnum.computed.getVal(), reason, externalUserDTO.getMemberId(), relationKey , PreDealTypeEnum.friend.getVal());
            dealSuccess(taskId, dataPre.getDataId(), dataPre.getpDataId(), wxEnterpriseId);
        } catch (WxApiLimitException e) {
            logger.info("接口次数限制：{}", JSONObject.toJSONString(dataPre));
            dealFlag = tryAgainToMq(dataPre);
            reason = "接口重试超出限制";
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("同步失败：{},{}", JSONObject.toJSONString(dataPre), e);
            reason = "第三方好友处理异常";
            dealFlag = false;
        } finally {
            if (!dealFlag) {
                dealException(dealParamMqDTO.getTaskId(), dataPre.getDataId(), dataPre.getpDataId(), reason, relationKey);
            }
        }
    }

    /**
     * 重试机制
     *
     * @param dataPre
     * @return
     */
    private boolean tryAgainToMq(TabHaobanPreDealLog dataPre) {
        logger.info("需要重试friend：{}", dataPre.getDataId());
        String key = TRY_AGAIN + dataPre.getTaskId() + ":" + dataPre.getDataId();
        Object cache = RedisUtil.getCache(key);
        if (null == cache) {
            RedisUtil.setCache(key, 1, 2L, TimeUnit.HOURS);
        } else {
            Integer count = Integer.valueOf(cache.toString());
            RedisUtil.setCache(key, count + 1);
            if (count > 4) {
                return false;
            }
        }
        HashSet<String> reTrysIds = new HashSet<>();
        reTrysIds.add(dataPre.getDataId());
        dealDepartmentToMq(dataPre.getTaskId(), reTrysIds, SyncTaskStatusEnum.friend_sync);
        return true;
    }

    private String dealMerge(ExternalUserDTO externalUserDTO, TabHaobanPreDealLog dataPre) {
        String wxEnterpriseId = dataPre.getWxEnterpriseId();
        String wxUserId = dataPre.getDataId().split("###")[1] ;
        if (externalUserDTO.getFriendType() == 2) {
            return "不是微信好友，是企业微信好友:" + externalUserDTO.getFriendType();
        }
        String staffId = dataPre.getpDataId() ;
        ClerkMainStoreRelatedDTO mainStore = clerkMainStoreRelatedApiService.getWxEnterpriseIdAndStaffId(wxEnterpriseId, staffId);
        if (mainStore == null) {
            return "主门店不存在";
        }
        StaffClerkRelationDTO staffClerkRelationDTO = staffClerkRelationService.getOneBindByStoreId(staffId, mainStore.getStoreId());
        if (staffClerkRelationDTO == null) {
            return "未绑定导购";
        }
        String enterpriseId = staffClerkRelationDTO.getEnterpriseId() ;
        TabHaobanWxEnterpriseRelated wxEnterpriseRelated = wxEnterpriseRelatedService.getByEnterpriseId(wxEnterpriseId, enterpriseId);
        if (wxEnterpriseRelated == null) {
            logger.info("没有存在企业关联：{},{}", wxEnterpriseId, enterpriseId);
            return "没有关联企业"; 
        }
        String storeId = mainStore.getStoreId() ;
        String clerkId = staffClerkRelationDTO.getClerkId() ;
        externalUserDTO.setWxEnterpriseId(wxEnterpriseId);
        externalUserDTO.setEnterpriseId(enterpriseId);
        externalUserDTO.setStoreId(storeId);
        externalUserDTO.setClerkId(clerkId);
        externalUserDTO.setWxUserId(wxUserId);
        externalUserDTO.setStaffId(staffId);

        boolean addByWelcome = this.wxEnterpriseRelatedService.getAddByWelcomeFlag(wxEnterpriseRelated,externalUserDTO.getUnionId(),false) ;
        if (addByWelcome) {
            logger.info("好友不同开平：{}", JSONObject.toJSONString(externalUserDTO));
            return memberUnionidRelatedApiService.addExternal(externalUserDTO);
        }
        String clerkCode = staffClerkRelationDTO.getClerkCode();
        ClerkDTO clerk = clerkService.getClerkByClerkCode(staffClerkRelationDTO.getEnterpriseId(), clerkCode);
        if (clerk == null) {
            return "导购不存在:" + clerkCode;
        }
        String qrcodeParam = clerk.getQrcodeParam();
        if (StringUtils.isBlank(qrcodeParam)) {
            logger.info("导购码不存在：" + clerkCode);
            qrcodeParam = "clerk_clerk_"+clerk.getClerkId() ;
        }
        QywxMemberQDTO qdto = new QywxMemberQDTO() ;
        qdto.setEnterpriseId(enterpriseId);
        qdto.setNick(externalUserDTO.getName());
        qdto.setPhotoUrl(externalUserDTO.getAvatar());
        qdto.setQrcodeParam(qrcodeParam);
        qdto.setUnionId(externalUserDTO.getUnionId());
        if(wxEnterpriseRelated.getWxEnterpriseType()==0) {
            qdto.setUserId(externalUserDTO.getExternalUserId());
        }
        qdto.setSence(1);
        String memberId = null;
        com.gic.api.base.commons.ServiceResponse<MemberSimpleDetailDTO> resp = this.memberEntranceApiService.enterpriseWechatByFriendEntrance(qdto);
        logger.info("加好友,创建member,resp={},param={}",JSON.toJSON(resp),JSON.toJSONString(qdto));
        if(resp.isSuccess()) {
            MemberSimpleDetailDTO member = resp.getResult() ;
            memberId = member.getMemberId() ;
        }
        if (memberId == null) {
            return "会员不存在:unionid:" + externalUserDTO.getUnionId();
        }
        externalUserDTO.setMemberId(memberId);
        return memberUnionidRelatedApiService.addExternal(externalUserDTO);
    }
    
    public void dealException(String taskId, String dataId, String pDataId, String reason, String relationKey) {
        preDealService.updateFriendStatusByDataId(taskId, dataId, PreDealStatusEnum.exception.getVal(), reason, null, relationKey, PreDealTypeEnum.friend.getVal());
        checkDepartmentTask(taskId, pDataId);
    }

    @Override
    public void dealException(String taskId, String dataId, String pDataId, String reason) {
        return;
    }

    @Override
    public void dealSuccess(String taskId, String dataId, String pDataId, String wxEnterpriseId) {
        //校验成功是否都
        checkDepartmentTask(taskId, pDataId);
    }

    /**
     * 自定义处理流程
     *
     * @param taskId
     * @param pDataId
     */
    public void checkDepartmentTask(String taskId, String pDataId) {
        //校验是否都已经处理完成
        boolean b = preDealService.checkFriendTaskByPDataId(taskId, pDataId, PreDealTypeEnum.friend.getVal());
        if (!b) {
            return;
        }
        logger.info("同步第三方服务商好友结束：{},{}", taskId, pDataId);
        String key = "haoban_sync_third_friend_task_" + taskId + ":" + pDataId;
        String lockKey = "haoban_sync_third_friend_task_lock_" + taskId + ":" + pDataId;
        RedisUtil.lock(lockKey, 3L);
        Object hasDealCheck = RedisUtil.getCache(key);
        if (hasDealCheck != null) {
            logger.info("重复提交结束第三方好友：{}", pDataId);
            RedisUtil.unlock(lockKey);
            return;
        }
        RedisUtil.setCache(key, pDataId, 30L, TimeUnit.SECONDS);
        TabHaobanPreDealLog preDealLog = preDealService.getByDataId(taskId, pDataId, PreDealTypeEnum.friend_clerk.getVal(), PreDealStatusEnum.dealing.getVal());
        if (preDealLog != null) {
            preDealService.updateStatusByDataId(taskId, pDataId, PreDealTypeEnum.friend_clerk.getVal(), PreDealStatusEnum.computed.getVal(), "成功");
            this.checkDepartmentTask(taskId);
        }
        RedisUtil.unlock(lockKey);
    }

    @Override
    public void checkDepartmentTask(String taskId) {
        friendClerkSyncNewOperation.checkDepartmentTask(taskId);
    }

    /**
     * 放入mq处理部门数据
     *
     * @param taskId
     * @param dealList
     */
    private void dealDepartmentToMq(String taskId, Set<String> dealList, SyncTaskStatusEnum syncTaskStatusEnum) {
        //预处理分组任务
        syncTaskService.updateTaskStatus(taskId, syncTaskStatusEnum.getVal());
        List<String> ret = dealList.stream().map(relationId -> {
            DealParamMqDTO dealParamMqDTO = new DealParamMqDTO();
            dealParamMqDTO.setData(relationId);
            dealParamMqDTO.setTaskId(taskId);
            dealParamMqDTO.setType(syncTaskStatusEnum.getVal());
            return JSONObject.toJSONString(dealParamMqDTO);
        }).collect(Collectors.toList());

        GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
        try {
            clientInstance.sendBatchMessages("departmentSyncDealMq", ret);
        } catch (Exception e) {
            logger.info("发送失败:{}", taskId, e);
            e.printStackTrace();
        }
    }
}
