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.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.MemberUnionidRelatedApiService;
import com.gic.haoban.manage.service.entity.TabHaobanPreDealLog;
import com.gic.haoban.manage.service.exception.WxApiLimitException;
import com.gic.haoban.manage.service.service.*;
import com.gic.haoban.manage.service.service.out.impl.DealSyncOperationApiServiceImpl;
import com.gic.haoban.manage.service.task.BaseSyncOperation;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;

import org.apache.commons.collections.CollectionUtils;
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;

    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 {
            if (dataPre.getStatusFlag() != PreDealStatusEnum.pre.getVal()) {
                logger.info("已经处理过，无需重复处理:{}", JSONObject.toJSONString(dataPre));
                return;
            }
            String wxEnterpriseId = dataPre.getWxEnterpriseId();
            String wxUserId =  dataPre.getDataId().split("###")[1] ;
            String taskId = dealParamMqDTO.getTaskId();
            String externalUserId = dataPre.getDataContent();
            String staffId = dataPre.getpDataId() ;
            
            ExternalUserDTO externalUserDTO = memberUnionidRelatedApiService.getExternalUseridInfo(wxEnterpriseId, wxUserId, externalUserId , 1);
            if (externalUserDTO == null) {
                logger.info("第三方外部联系人详情查询失败,staffId={},{},{}", staffId,wxUserId,externalUserId);
                dealFlag = false;
                reason = "好友不存在";
                return;
            }
            String str = staffId + "_" + externalUserDTO.getName() + "_" + externalUserDTO.getAddCreateTime() ;
            relationKey = SecureUtil.md5(str);
            logger.info("生成第三方relationKey={},staff={},{}",relationKey,staffId,str);
            
            // 根据关联键relationkey查看自建应用 是否有数据
            List<TabHaobanPreDealLog> list = this.preDealService.getByRelationKey(taskId, PreDealTypeEnum.self_friend.getVal(), relationKey);
            if(CollectionUtils.isEmpty(list)) {
                logger.info("用户的代开发不存在关联数据：{},{}", JSONObject.toJSONString(dataPre), JSONObject.toJSONString(externalUserDTO));
                dealFlag = false;
                reason = "用户的代开发应用不存在该数据：" + relationKey;
                return;
            }
            if(list.size()>1) {
                logger.info("用户的代开发应用数据多条：{},{}", JSONObject.toJSONString(dataPre), JSONObject.toJSONString(externalUserDTO));
                dealFlag = false;
                reason = "用户的代开发应用数据多条：" + relationKey;
                return;
            }
            TabHaobanPreDealLog selfPre = list.get(0) ;
            logger.info("代开发的数据={}",selfPre.getDataContent());
            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 =  this.memberUnionidRelatedApiService.dealMergeForReflsh(externalUserDTO, wxEnterpriseId, staffId) ;
            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) {
            logger.info("同步失败：{},{}", JSONObject.toJSONString(dataPre), e);
            reason = "第三方好友处理异常";
            dealFlag = false;
        } finally {
            if (!dealFlag) {
                dealException(dealParamMqDTO.getTaskId(), dataPre.getDataId(), dataPre.getpDataId(), reason, relationKey);
            }
        }
    }

    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) {
        this.preDealService.addTaskStaffStatusCache(taskId,pDataId,8);
    }

    @Override
    public void checkDepartmentTask(String taskId) {
    }

    private boolean tryAgainToMq(TabHaobanPreDealLog dataPre) {
        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 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);
        }
    }
}
