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.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.commons.util.ToolUtil;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.dto.StoreGroupDTO;
import com.gic.enterprise.api.service.StoreGroupService;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.base.api.common.BasePageInfo;
import com.gic.haoban.common.utils.EntityUtil;
import com.gic.haoban.manage.api.dto.*;
import com.gic.haoban.manage.api.enums.*;
import com.gic.haoban.manage.api.service.DealSyncOperationApiService;
import com.gic.haoban.manage.service.dao.mapper.StaffMapper;
import com.gic.haoban.manage.service.entity.*;
import com.gic.haoban.manage.service.service.*;
import com.gic.haoban.manage.service.service.impl.PreDealServiceImpl;
import com.gic.haoban.manage.service.task.BaseSyncOperation;
import com.gic.haoban.manage.service.util.CustomSwitcher;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;
import com.gic.wechat.api.service.qywx.QywxDepartmentApiService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * Created 2020/4/9.
 *
 * @author hua
 */
@Service
public class DealSyncOperationApiServiceImpl implements DealSyncOperationApiService {

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

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private StoreGroupService storeGroupService;

    @Autowired
    private PreDealService preDealService;

    @Autowired
    private SyncTaskService syncTaskService;

    @Autowired
    private StoreService storeService;

    @Autowired
    private Map<String, BaseSyncOperation> operationMap;

    @Autowired
    private StaffService staffService;
    @Autowired
    private StaffMapper staffMapper ;

    @Autowired
    private StaffDepartmentRelatedService staffDepartmentRelatedService;

    @Autowired
    private ClerkService clerkService;

    @Autowired
    private QywxDepartmentApiService qywxDepartmentApiService;

    @Autowired
    private WxEnterpriseService wxEnterpriseService;

    @Autowired
    private StaffClerkRelationService staffClerkRelationService;

    @Autowired
    private SecretSettingService secretSettingService;

    private static final String LOCK_KEY = "sync_wx_lock_";

    private static final String LOCK_SUCCESS_KEY = "sync_wx_success_lock_";

    public static final String FRIEND_LOCK = "haoban_fresh_wx_friend_lock_";

    private static final String FRIEND_TAG_LOCK = "haoban_sync_tag_lock_";

    @Override
    public void departmentDealMq(String params) {
        DealParamMqDTO dealParamMqDTO = JSONObject.parseObject(params, DealParamMqDTO.class);
        TabHaobanPreDealLog dataPre = preDealService.getByDataId(dealParamMqDTO.getTaskId(), dealParamMqDTO.getData(), dealParamMqDTO.getType() - 1, PreDealStatusEnum.all.getVal());
        logger.info("好办同步处理mq处理开始:{}，dataPre={}", params,JSON.toJSONString(dataPre));
        if (dataPre == null) {
            return;
        }
        Integer dataType = dataPre.getDataType();
        logger.info("同步类型,dataType:{}",dataType);
        if (dataType.equals(PreDealTypeEnum.dept.getVal())) {
            logger.info("0 部门处理：{}", params);
            operationMap.get("qywxDeptSyncOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if (dataType.equals(PreDealTypeEnum.clerk.getVal())) {
            logger.info("2 成员处理：{}", params);
            operationMap.get("qywxStaffSyncOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if (dataType.equals(PreDealTypeEnum.friend_clerk.getVal())) {
            logger.info("6 好友导购处理：{}", params);
            operationMap.get("friendClerkSyncNewOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if (dataType.equals(PreDealTypeEnum.friend.getVal())) {
            logger.info("8 第三方好友处理：{}", params);
            operationMap.get("friendSyncNewOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if (dataType.equals(PreDealTypeEnum.self_friend.getVal())) {
            logger.info("7 自建好友处理：{}", params);
            operationMap.get("selfFriendSyncNewOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if (dataType.equals(PreDealTypeEnum.tag.getVal())) {
            logger.info("10 会员标签处理：{}", params);
            operationMap.get("friendTagSyncOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if (dataType.equals(PreDealTypeEnum.tag_member.getVal())) {
            logger.info("11 会员标签处理标签项：{}", params);
            operationMap.get("friendMemberTagSyncOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        } else if(dataType.equals(PreDealTypeEnum.modify_hm.getVal())) {
            logger.info("20 活码批量修改");
            operationMap.get("qwHmOperation").dealSingleByMq(dealParamMqDTO, dataPre);
        }else {
            logger.info("不是正常数据类型:{}", params);
        }
    }

    @Override
    public void departmentDealMq2(String params) {
        this.departmentDealMq(params) ;
    }


    @Override
    public void dealDepartment(String taskId, String wxEnterpriseId
            , List<SyncSingleDealDTO> addList, List<SyncSingleDealDTO> editList) {

        logger.info("初始开始:{}", taskId);
        //处理修改
        dealEidtSync(editList);

        if (CollectionUtils.isEmpty(addList)) {
            syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.compute.getVal());
            unlockTask(wxEnterpriseId);
            return;
        }
        logger.info("处理分组信息开始：{}", taskId);
        dealAddSync(taskId, wxEnterpriseId, addList);

        //加入队列处理
        logger.info("初始化到队列：{}", taskId);
        dealDepartmentInit(taskId, wxEnterpriseId, addList);

    }

    @Override
    public void reDealDepartment(String taskId, int dataType) {
        logger.info("开始重新同步:{}", taskId);
        TabHaobanSyncTask task = syncTaskService.getSyncTask(taskId);
        if (null == task) {
            logger.info("任务不存在!{}", taskId);
            return;
        }
        if ((!task.getStatusFlag().equals(SyncTaskStatusEnum.exception_close.getVal())) &&
                (!task.getStatusFlag().equals(SyncTaskStatusEnum.exception_compute.getVal()))) {
            logger.info("任务不在没有在异常状态!{}", taskId);
            return;
        }

        int groupErrCount = preDealService.countExcepAndPreByTaskId(taskId, PreDealTypeEnum.dept.getVal());
        int storeErrCount = preDealService.countExcepAndPreByTaskId(taskId, PreDealTypeEnum.store.getVal());
        List<TabHaobanPreDealLog> list = null;
        if (dataType == -1) {
            if (groupErrCount > 0) {
                dataType = PreDealTypeEnum.dept.getVal();
                list = preDealService.queryDepartRebuildDealLog(taskId);
            } else if (storeErrCount > 0) {
                dataType = PreDealTypeEnum.store.getVal();
                list = preDealService.listRebuildByTaskId(taskId, dataType);
            } else {
                dataType = PreDealTypeEnum.clerk.getVal();
                list = preDealService.listRebuildByTaskId(taskId, dataType);
            }
        }
        if (CollectionUtils.isEmpty(list)) {
            unlockTask(task.getWxEnterpriseId());
            return;
        }
        Set<String> midList = list.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toSet());
        //根据类型获取状态
        SyncTaskStatusEnum syncTaskStatusEnum = (dataType == PreDealTypeEnum.dept.getVal() ? SyncTaskStatusEnum.group_sync
                : (dataType == PreDealTypeEnum.store.getVal() ? SyncTaskStatusEnum.store_sync : SyncTaskStatusEnum.clerk_sync));
        logger.info("处理开始:类型:{}", syncTaskStatusEnum.getVal());
        //处理预处理数据
        preDealService.updateExceptionToPre(taskId);
        sendToMq(taskId, midList, syncTaskStatusEnum,null);
    }


    private String createBaseTask(String wxEnterpriseId, String taskName, String userId, String desc, int taskType) {
        String key = "sync_create_task_" + wxEnterpriseId;
        RedisUtil.lock(key, 10L);
        String taskLock = getTaskLock(wxEnterpriseId);
        if (StringUtils.isNotBlank(taskLock)) {
            logger.info("在处理中,返回");
            RedisUtil.unlock(key);
            return null;
        }
        TabHaobanSyncTask tabHaobanSyncTask = new TabHaobanSyncTask();
        tabHaobanSyncTask.setAddUser(userId);
        tabHaobanSyncTask.setTaskName(taskName);
        tabHaobanSyncTask.setTaskDesc(desc);
        tabHaobanSyncTask.setWxEnterpriseId(wxEnterpriseId);
        tabHaobanSyncTask.setStatusFlag(SyncTaskStatusEnum.init.getVal());
        tabHaobanSyncTask.setTaskId(ToolUtil.randomUUID());
        tabHaobanSyncTask.setTaskType(taskType);
        syncTaskService.createTask(tabHaobanSyncTask);
        lockTask(wxEnterpriseId, tabHaobanSyncTask.getTaskId());
        RedisUtil.unlock(key);
        return tabHaobanSyncTask.getTaskId();

    }

    @Override
    public String createTask(String wxEnterpriseId, String taskName, String userId, String desc) {
        return createBaseTask(wxEnterpriseId, taskName, userId, desc, 0);

    }

    @Override
    public String createQywxTask(String wxEnterpriseId, String taskName, String userId, String desc) {
        return createBaseTask(wxEnterpriseId, taskName, userId, desc, SyncTaskTypeEnum.QYWX_CONTACT.getType());

    }


    /**
     * 处理修改数据
     *
     * @param editList
     */
    private void dealEidtSync(List<SyncSingleDealDTO> editList) {
        if (CollectionUtils.isEmpty(editList)) {
            return;
        }
        //先处理修改的
        editList.forEach(syncSingleDealDTO -> {
            TabHaobanDepartment department = departmentService.selectById(syncSingleDealDTO.getDepartmentId());
            if (!department.getParentDepartmentId().equals(syncSingleDealDTO.getParentDepartmentId())) {
                department.setParentDepartmentId(syncSingleDealDTO.getParentDepartmentId());
                departmentService.edit(EntityUtil.changeEntityByJSON(DepartmentDTO.class, department));
            }
        });
    }

    /**
     * 执行新增同步
     *
     * @param taskId
     * @param wxEnterpriseId
     * @param addList
     */
    private void dealAddSync(String taskId, String wxEnterpriseId, List<SyncSingleDealDTO> addList) {

        Map<String, String> pMap = addList.stream().collect(Collectors.toMap(SyncSingleDealDTO::getRelatedId, SyncSingleDealDTO::getParentDepartmentId));
        //获取企业与分组map
        Map<String, List<String>> eidListMap = addList.stream().filter(dto -> {
            String departmentId = dto.getDepartmentId();
            TabHaobanDepartment department = departmentService.selectById(departmentId);
            if (department != null) {
                return false;
            }
            Integer storeFlag = dto.getStoreFlag();
            return !storeFlag.equals(1);
        }).collect(Collectors.groupingBy(SyncSingleDealDTO::getEnterpriseId
                , Collectors.mapping(SyncSingleDealDTO::getRelatedId, Collectors.toList())));

        //放入预处理表
        eidListMap.forEach((k, v) -> {
            //获取所有分组列表
            List<StoreGroupDTO> groupDTOList = storeGroupService.listStoreGroupAndChildren(v.toArray(new String[]{}), k);
            List<String> hasKey = new ArrayList<>();
            List<TabHaobanPreDealLog> dealList = groupDTOList.stream().filter(dto -> {
                return !hasKey.contains(dto.getStoreGroupId());
            }).map(storeGroupDTO -> {
                TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
                dealLog.setDataId(storeGroupDTO.getStoreGroupId());
                if (pMap.containsKey(storeGroupDTO.getStoreGroupId())) {
                    dealLog.setpDataId(pMap.get(storeGroupDTO.getStoreGroupId()));
                } else {
                    dealLog.setpDataId(storeGroupDTO.getParentGroupId());
                }
                dealLog.setDataType(PreDealTypeEnum.dept.getVal());
                dealLog.setStatusFlag(0);
                dealLog.setTaskId(taskId);
                dealLog.setEnterpriseId(storeGroupDTO.getEnterpriseId());
                dealLog.setWxEnterpriseId(wxEnterpriseId);
                return dealLog;
            }).collect(Collectors.toList());

            preDealService.insert(dealList);
        });

        //处理门店信息
        List<TabHaobanPreDealLog> storeList = addList.stream().filter(dto -> {
            return dto.getStoreFlag() == 1;
        }).map(dto -> {
            TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
            dealLog.setDataId(dto.getRelatedId());
            dealLog.setpDataId(dto.getParentDepartmentId());
            dealLog.setDataType(1);
            dealLog.setStatusFlag(0);
            dealLog.setEnterpriseId(dto.getEnterpriseId());
            dealLog.setTaskId(taskId);
            dealLog.setWxEnterpriseId(wxEnterpriseId);
            return dealLog;
        }).collect(Collectors.toList());

        preDealService.insert(storeList);
    }

    /**
     * 初始化部门
     *
     * @param taskId
     * @param wxEnterpriseId
     * @param addList
     */
    private void dealDepartmentInit(String taskId, String wxEnterpriseId, List<SyncSingleDealDTO> addList) {
        Set<String> addListMid = addList.stream().filter(dto -> dto.getStoreFlag().equals(0)).map(dto -> dto.getRelatedId()).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(addListMid)) {
            sendToMq(taskId, addListMid, SyncTaskStatusEnum.group_sync,null);
        } else {
            addListMid = addList.stream().filter(dto -> dto.getStoreFlag().equals(1)).map(dto -> dto.getRelatedId()).collect(Collectors.toSet());
            sendToMq(taskId, addListMid, SyncTaskStatusEnum.store_sync,null);
        }
    }

    /**
     * 放入mq处理部门数据
     *
     * @param taskId
     * @param
     */



    public String lockTask(String wxEnterpriseId, String taskId) {
        String key = LOCK_KEY + wxEnterpriseId;
        Object cache = RedisUtil.getCache(key);
        if (null == cache) {
            logger.info("设置通讯录缓存={},{}",key,taskId);
            RedisUtil.setCache(key, taskId, 3L, TimeUnit.HOURS);
            return taskId;
        }
        return null;
    }

    @Override
    public boolean closeTask(String wxEnterpriseId) {
        String taskId = getTaskLock(wxEnterpriseId);
        if (taskId != null) {
            syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.exception_close.getVal());
            unlockTask(wxEnterpriseId);
        }
        return true;
    }

    @Override
    public void unlockTask(String wxEnterpriseId) {
        String key = LOCK_KEY + wxEnterpriseId;
        String taskId = (String) RedisUtil.getCache(key);
        if (StringUtils.isNotBlank(taskId)) {
            TabHaobanSyncTask syncTask = syncTaskService.getSyncTask(taskId);
            if (syncTask.getStatusFlag().equals(SyncTaskStatusEnum.compute.getVal())) {
                String sKey = LOCK_SUCCESS_KEY + wxEnterpriseId;
                RedisUtil.setCache(sKey, taskId);
            }
        }
        logger.info("删除通讯录缓存={},{}",key,taskId);
        RedisUtil.delCache(key);
    }

    @Override
    public String getTaskLock(String wxEnterpriseId) {
        String key = LOCK_KEY + wxEnterpriseId;
        String v = (String) RedisUtil.getCache(key);
        logger.info("查询通讯录缓存key={},{}",key,v);
        return v ;
    }

    @Override
    public SyncCheckDTO getTaskCheck(String wxEnterpriseId) {
        String taskId = getTaskLock(wxEnterpriseId);
        SyncCheckDTO syncCheckDTO = new SyncCheckDTO();
        String sKey = LOCK_SUCCESS_KEY + wxEnterpriseId;
        if (null == taskId) {
            taskId = (String) RedisUtil.getCache(sKey);
            RedisUtil.delCache(sKey);
        }
        if (null == taskId) {
            return syncCheckDTO;
        }
        TabHaobanSyncTask syncTask = syncTaskService.getSyncTask(taskId);
        if(Arrays.asList(4,5,6).contains(syncTask.getStatusFlag())) {
            RedisUtil.delCache(sKey);
            return syncCheckDTO;
        }
        /*int status = syncTask.getStatusFlag() ;
        if(status != 4) {
           int count = this.preDealService.countByTaskId(taskId) ;
           if(count <= 0) {
               this.syncTaskService.updateTaskStatus(taskId,4) ;
           }
        }*/
        syncCheckDTO.setSyncStatus(syncTask.getStatusFlag());

        PreDealLogInfoDTO dealLogInfoDTO = preDealService.getLastPreDataByTaskId(taskId);
        if (dealLogInfoDTO == null) {
            RedisUtil.delCache(sKey);
            return syncCheckDTO;
        }
        //30分钟内没执行就重试 并在一天内
        Date date = DateUtils.addMinutes(new Date(), -30);
        Date dayDate = DateUtils.addDays(new Date(), -1);

        if (dealLogInfoDTO != null && dealLogInfoDTO.getUpdateTime() != null
                && dealLogInfoDTO.getCreateTime() != null
                && dealLogInfoDTO.getUpdateTime().before(date)
                && syncTask.getUpdateTime().before(date)
                && syncTask.getCreateTime().after(dayDate)) {
            logger.info("重试：{}", taskId);
            syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.exception_close.getVal());
            reDealDepartment(taskId, -1);
            return syncCheckDTO;
        }


        int totalCount = preDealService.countByTaskId(taskId, -1, -1);
        int groupErrCount = preDealService.countByTaskId(taskId, PreDealTypeEnum.dept.getVal(), PreDealStatusEnum.exception.getVal());
        int storeErrCount = preDealService.countByTaskId(taskId, PreDealTypeEnum.store.getVal(), PreDealStatusEnum.exception.getVal());
        int clerkErrCount = preDealService.countByTaskId(taskId, PreDealTypeEnum.clerk.getVal(), PreDealStatusEnum.exception.getVal());
        int preCount = preDealService.countByTaskId(taskId, -1, PreDealStatusEnum.pre.getVal());

        syncCheckDTO.setTotalDeal(totalCount);
        syncCheckDTO.setGroupErrCount(groupErrCount);
        syncCheckDTO.setStoreErrCount(storeErrCount);
        syncCheckDTO.setStaffErrCount(clerkErrCount);
        syncCheckDTO.setHasDeal(totalCount - preCount);
        return syncCheckDTO;
    }

    @Override
    public Page<SyncTaskDTO> listSyncTask(String wxEnterpriseId, BasePageInfo pageInfo) {
        Page<SyncTaskDTO> page = syncTaskService.listTaskPage(wxEnterpriseId, pageInfo);
        if (CollectionUtils.isEmpty(page.getResult())) {
            return page;
        }
        List<SyncTaskDTO> result = page.getResult();
        for (SyncTaskDTO dto : result) {
            String addUser = dto.getAddUser();
            TabHaobanStaff haobanStaff = staffService.selectById(addUser);
            if (null != haobanStaff) {
                dto.setUserName(haobanStaff.getStaffName());
            } else {
                dto.setUserName("系统管理员");
            }
        }
        return page;
    }

    @Override
    public Page<PreDealLogInfoDTO> listSyncTaskDetail(String wxEnterpriseId, String taskId, BasePageInfo pageInfo) {
        TabHaobanSyncTask syncTask = syncTaskService.getSyncTask(taskId);
        Page<PreDealLogInfoDTO> page = preDealService.listExceptionByTaskId(taskId, pageInfo);
        if (CollectionUtils.isEmpty(page.getResult())) {
            return page;
        }
        //gic同步微信
        if (syncTask.getTaskType().equals(0)) {
            List<PreDealLogInfoDTO> result = page.getResult();
            for (PreDealLogInfoDTO dto : result) {
                if (dto.getDataType().equals(PreDealTypeEnum.dept.getVal())) {
                    StoreGroupDTO midGroup = storeGroupService.getStoreGroupById(dto.getDataId());
                    if (midGroup != null) {
                        dto.setDataName(midGroup.getStoreGroupName());
                        dto.setChainName(midGroup.getStoreGroupNameLevel());
                    }
                } else if (dto.getDataType().equals(PreDealTypeEnum.store.getVal())) {
                    StoreDTO store = storeService.getStore(dto.getDataId());
                    if (null != store) {
                        dto.setDataName(store.getStoreName());
                        dto.setChainName(store.getStoreGroupName());
                        dto.setDataCode(store.getStoreCode());
                    }
                } else if (dto.getDataType().equals(PreDealTypeEnum.clerk.getVal())) {
                    ClerkDTO clerkDTO = clerkService.getClerkByClerkId(dto.getDataId());
                    if (null != clerkDTO) {
                        dto.setDataName(clerkDTO.getClerkName());
                        dto.setChainName(clerkDTO.getStoreName());
                        dto.setDataCode(clerkDTO.getClerkCode());
                    }
                }
            }
        } else if (syncTask.getTaskType().equals(2)) {
            List<PreDealLogInfoDTO> result = page.getResult();
            for (PreDealLogInfoDTO dto : result) {
                dto.setDataCode(dto.getDataId());
                TabHaobanStaff staff = staffService.selectByUserIdAndEnterpriseId(dto.getpDataId(), wxEnterpriseId);
                if (staff != null) {
                    dto.setDataName(staff.getStaffName());
                }
            }
        } else {
            List<PreDealLogInfoDTO> result = page.getResult();
            for (PreDealLogInfoDTO dto : result) {
                dto.setDataCode(dto.getDataId());
                dto.setDataName(dto.getDataContent());
            }
        }
        return page;
    }

    // 同步通讯录
    @Override
    public String dealQywxDepartment(String taskId, String wxEnterpriseId) {
        logger.info("同步通讯录开始={},taskId={}",wxEnterpriseId,taskId);
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId) ;
        SecretSettingDTO secretSetting = secretSettingService.getSecretSetting(qwDTO.getWxEnterpriseId(), SecretTypeEnum.CUSTOMIZED_APP.getVal());
        if (null == secretSetting || null == secretSetting.getCheckFlag() || secretSetting.getCheckFlag() == 0) {
            logger.info("没有配置secret");
            syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.exception_close.getVal());
            unlockTask(wxEnterpriseId);
            return "没有配置secret";
        }
        Map<String,Integer> map = CustomSwitcher.haoban_department_id ;
        int id = 1 ;
        if(null != map && null != map.get(wxEnterpriseId)) {
            id = map.get(wxEnterpriseId) ;
        }
        logger.info("id={}",id);
        List<com.gic.wechat.api.dto.qywx.DepartmentDTO> list = qywxDepartmentApiService.listSelfDepartment(qwDTO.getDkCorpid(), secretSetting.getSecretVal(), id,qwDTO.getUrlHost());
        if (CollectionUtils.isEmpty(list)) {
            logger.info("企微部门数量0,退出同步");
            syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.exception_close.getVal());
            unlockTask(wxEnterpriseId);
            return "没有数据同步或权限没设置全部";
        }
        logger.info("企微部门数={}",list.size());
        final int _id = id ;
        syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.group_sync.getVal());
        List<TabHaobanPreDealLog> dealLogList = list.stream().map(dto -> {
            TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
            dealLog.setDataId(dto.getId().toString());
            if(dto.getId().toString().equals(_id+"")) {
                dealLog.setpDataId("0");
                dto.setParentid(0);
            }else {
                dealLog.setpDataId(dto.getParentid().toString());
            }
            dealLog.setDataType(0);
            dealLog.setStatusFlag(0);
            dealLog.setTaskId(taskId);
            dealLog.setDataContent(JSONObject.toJSONString(dto));
            dealLog.setWxEnterpriseId(wxEnterpriseId);
            return dealLog;
        }).collect(Collectors.toList());
        // 保存部门数据
        preDealService.insert(dealLogList);
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add(""+id);
        sendToMq(taskId, hashSet, SyncTaskStatusEnum.group_sync,"departmentSyncDealMq2");
        return null;
    }


    @Override
    public void cleanDiffrence(String wxEnterpriseId, String taskId) {
        List<TabHaobanPreDealLog> groupList = preDealService.listByTaskId(taskId, PreDealTypeEnum.dept.getVal(), PreDealStatusEnum.computed.getVal());
        List<TabHaobanPreDealLog> clerkList = preDealService.listByTaskId(taskId, PreDealTypeEnum.clerk.getVal(), PreDealStatusEnum.computed.getVal());

        //清空staff
        if (CollectionUtils.isNotEmpty(clerkList)) {
            List<String> clerkIds = clerkList.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toList());
            List<StaffDTO> retLists = staffService.listByUserIdsAndWxEnterpriseId(clerkIds, wxEnterpriseId);
            List<String> staffIds = retLists.stream().map(StaffDTO::getStaffId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(staffIds)) {
                List<String> delStaffIds = staffService.listDelUserStaffId(wxEnterpriseId, staffIds);
                if (CollectionUtils.isEmpty(delStaffIds)) {
                    logger.info("没有要删除的用户：{}--{}", wxEnterpriseId, taskId);
                } else {
                    staffClerkRelationService.cleanStaffClerk(wxEnterpriseId, delStaffIds);
                    staffService.cleanStaff(wxEnterpriseId, delStaffIds);
                    staffDepartmentRelatedService.cleanStaffDepartment(wxEnterpriseId, delStaffIds);
                }
            }
        }

        //清空cleak
        if (CollectionUtils.isNotEmpty(groupList)) {
            List<String> groupIdList = groupList.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toList());
            departmentService.cleanDepartment(wxEnterpriseId, groupIdList);
        }

        RedisUtil.delLocalCache("department-list-cache-" + wxEnterpriseId);

    }


    @Override
    public String createWxFriendTask(String wxEnterpriseId, String taskName, String staffId, String desc) {
        TabHaobanSyncTask tabHaobanSyncTask = new TabHaobanSyncTask();
        tabHaobanSyncTask.setAddUser(staffId);
        tabHaobanSyncTask.setTaskName(taskName);
        tabHaobanSyncTask.setTaskDesc(desc);
        tabHaobanSyncTask.setWxEnterpriseId(wxEnterpriseId);
        tabHaobanSyncTask.setStatusFlag(SyncTaskStatusEnum.init.getVal());
        tabHaobanSyncTask.setTaskId(ToolUtil.randomUUID());
        tabHaobanSyncTask.setTaskType(2);
        syncTaskService.createTask(tabHaobanSyncTask);
        lockTask(wxEnterpriseId, tabHaobanSyncTask.getTaskId());
        return tabHaobanSyncTask.getTaskId();
    }

    @Override
    public void dealWxFriendClerk(String taskId, String wxEnterpriseId) {
        List<TabHaobanStaff>  list = this.staffMapper.listByWxEnterpriseId(wxEnterpriseId) ;
        List<TabHaobanPreDealLog> dealLogList = list.stream().map(dto -> {
            TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
            dealLog.setDataId(dto.getStaffId());
            dealLog.setpDataId(dto.getStaffId());
            dealLog.setDataType(PreDealTypeEnum.friend_clerk.getVal());
            dealLog.setStatusFlag(0);
            dealLog.setTaskId(taskId);
            dealLog.setDataContent(JSONObject.toJSONString(dto));
            dealLog.setWxEnterpriseId(wxEnterpriseId);
            return dealLog;
        }).collect(Collectors.toList());

        preDealService.insert(dealLogList);
        HashSet<String> hashSet = (HashSet<String>) dealLogList.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toSet());
        sendToMq(taskId, hashSet, SyncTaskStatusEnum.friend_clerk_sync,"friendSyncDealMq");
    }

    @Override
    public String createWxFriendTaskSingle(String wxEnterpriseId, String taskName, String staffId, String staffName, int syncTaskType) {
        String lockKey = FRIEND_LOCK + "_lock_" + staffId;
        String staffLockKey = FRIEND_LOCK + staffId;
        RedisUtil.lock(lockKey, 2L);

        Object cache = RedisUtil.getCache(staffLockKey);
        if (null != cache) {
            RedisUtil.unlock(lockKey);
            logger.info("限制此操作,lockKey={}",staffLockKey);
            return null;
        }
        TabHaobanSyncTask tabHaobanSyncTask = new TabHaobanSyncTask();
        tabHaobanSyncTask.setAddUser(staffId);
        tabHaobanSyncTask.setTaskName(SyncTaskTypeEnum.getTaskName(syncTaskType));
        tabHaobanSyncTask.setTaskDesc(staffName);
        tabHaobanSyncTask.setWxEnterpriseId(wxEnterpriseId);
        tabHaobanSyncTask.setStatusFlag(SyncTaskStatusEnum.init.getVal());
        tabHaobanSyncTask.setTaskId(ToolUtil.randomUUID());
        tabHaobanSyncTask.setTaskType(syncTaskType);
        syncTaskService.createTask(tabHaobanSyncTask);
        RedisUtil.setCache(staffLockKey, tabHaobanSyncTask.getTaskId(), 1L, TimeUnit.HOURS);
        RedisUtil.unlock(lockKey);
        return tabHaobanSyncTask.getTaskId();
    }


    @Override
    public void dealWxFriendClerkSingle(String taskId, String wxUserId, String staffId, String wxEnterpriseId) {
        TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
        // 改成使用staffid
        dealLog.setDataId(staffId);
        dealLog.setpDataId(staffId);
        dealLog.setDataType(PreDealTypeEnum.friend_clerk.getVal());
        dealLog.setStatusFlag(0);
        dealLog.setTaskId(taskId);
        dealLog.setDataContent("刷新" + staffId);
        dealLog.setWxEnterpriseId(wxEnterpriseId);
        List<TabHaobanPreDealLog> dealLogList = new ArrayList<TabHaobanPreDealLog>();
        dealLogList.add(dealLog);
        preDealService.insert(dealLogList);
        HashSet<String> hashSet = (HashSet<String>) dealLogList.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toSet());
        sendToMq(taskId, hashSet, SyncTaskStatusEnum.friend_clerk_sync,null);
    }

    @Override
    public void dealWxFriendStore(String taskId, String storeId, String wxEnterpriseId) {
        List<StaffClerkRelationDTO> clerkRelationDTOS = staffClerkRelationService.listBindByStoreId(wxEnterpriseId, storeId);
        if (CollectionUtils.isEmpty(clerkRelationDTOS)) {
            logger.info("没有要刷新的：{},{}", wxEnterpriseId, storeId);
            return;
        }
        logger.info("查询到需要刷新的导购={},storeId={}",clerkRelationDTOS.size(),storeId);
        List<TabHaobanPreDealLog> dealLogList = clerkRelationDTOS.stream().map(dto -> {
            TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
            dealLog.setDataId(dto.getStaffId());
            dealLog.setpDataId(dto.getStaffId());
            dealLog.setDataType(PreDealTypeEnum.friend_clerk.getVal());
            dealLog.setStatusFlag(0);
            dealLog.setTaskId(taskId);
            dealLog.setWxEnterpriseId(wxEnterpriseId);
            return dealLog;
        }).collect(Collectors.toList());
        preDealService.insert(dealLogList);
        Set<String> hashSet = dealLogList.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toSet());
        sendToMq(taskId, hashSet, SyncTaskStatusEnum.friend_clerk_sync,null);
    }

    @Override
    public void quartWxFriendClerk(String res) {
        List<TabHaobanSyncTask> taskList = syncTaskService.listTaskByType(2);
        if (CollectionUtils.isNotEmpty(taskList)) {
            for (TabHaobanSyncTask tabHaobanSyncTask : taskList) {
                dealWxFriendClerk(tabHaobanSyncTask.getTaskId(), tabHaobanSyncTask.getWxEnterpriseId());
            }
        }
    }
    @Override
    public void sendToMq(String taskId, Set<String> dealList, SyncTaskStatusEnum syncTaskStatusEnum , String mqName) {
        //预处理分组任务
        if(StringUtils.isEmpty(mqName)) {
            mqName = "departmentSyncDealMq" ;
        }
        // 通讯录同步不要更新状态
        if(!(syncTaskStatusEnum.equals(SyncTaskStatusEnum.clerk_sync) || syncTaskStatusEnum.equals(SyncTaskStatusEnum.group_sync))) {
            syncTaskService.updateTaskStatus(taskId, syncTaskStatusEnum.getVal());
        }
        List<String> listRet = dealList.stream().map(relationId -> {
            DealParamMqDTO dealParamMqDTO = new DealParamMqDTO();
            dealParamMqDTO.setTaskId(taskId);
            dealParamMqDTO.setData(relationId);
            dealParamMqDTO.setType(syncTaskStatusEnum.getVal());
            return JSONObject.toJSONString(dealParamMqDTO);
        }).collect(Collectors.toList());

        GicMQClient clientInstance = GICMQClientUtil.getClientInstance();
        try {
            logger.info("放入mq={},{}",mqName,JSON.toJSONString(listRet));
            clientInstance.sendBatchMessages(mqName, listRet, 10);
        } catch (Exception e) {
            logger.info("发送失败:{},{}", taskId, JSONObject.toJSONString(listRet),e);
        }
    }

    @Override
    public boolean getFreshFriendSyncTask(String wxEnterpriseId, String staffId) {
        String staffLockKey = FRIEND_LOCK + staffId;
        Object cache = RedisUtil.getCache(staffLockKey);
        return null != cache;
    }

    @Override
    public String createTagTask(String wxEnterpriseId, String addUser, String memberTagId) {
        String lockKey = FRIEND_TAG_LOCK + "_lock_" + memberTagId;
        String staffLockKey = FRIEND_TAG_LOCK + memberTagId;
        RedisUtil.lock(lockKey, 2L);

        Object cache = RedisUtil.getCache(staffLockKey);
        if (null != cache) {
            RedisUtil.unlock(lockKey);
            return null;
        }
        TabHaobanSyncTask tabHaobanSyncTask = new TabHaobanSyncTask();
        tabHaobanSyncTask.setAddUser(addUser);
        tabHaobanSyncTask.setTaskName(SyncTaskTypeEnum.MEMBER_TAG.getTaskName());
        tabHaobanSyncTask.setTaskDesc(memberTagId);
        tabHaobanSyncTask.setWxEnterpriseId(wxEnterpriseId);
        tabHaobanSyncTask.setStatusFlag(SyncTaskStatusEnum.init.getVal());
        tabHaobanSyncTask.setTaskId(ToolUtil.randomUUID());
        tabHaobanSyncTask.setTaskType(SyncTaskTypeEnum.MEMBER_TAG.getType());
        syncTaskService.createTask(tabHaobanSyncTask);
        RedisUtil.setCache(staffLockKey, tabHaobanSyncTask.getTaskId(), 1L, TimeUnit.HOURS);
        RedisUtil.unlock(lockKey);
        return tabHaobanSyncTask.getTaskId();
    }

    @Override
    public void dealTagTask(String wxEnterpriseId, String enterpriseId, List<String> tagIds, String taskId) {
        TabHaobanSyncTask syncTask = syncTaskService.getSyncTask(taskId);
        if (CollectionUtils.isEmpty(tagIds)) {
            syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.compute.getVal());
            return;
        }
        List<TabHaobanPreDealLog> dealLogList = tagIds.stream().map(tagId -> {
            TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
            dealLog.setDataId(tagId);
            dealLog.setpDataId(syncTask.getTaskDesc());
            dealLog.setDataType(PreDealTypeEnum.friend_clerk.getVal());
            dealLog.setStatusFlag(0);
            dealLog.setTaskId(taskId);
            dealLog.setWxEnterpriseId(wxEnterpriseId);
            return dealLog;
        }).collect(Collectors.toList());
        preDealService.insert(dealLogList);
        Set<String> hashSet = dealLogList.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toSet());
        sendToMq(taskId, hashSet, SyncTaskStatusEnum.tag,null);
    }

    /**
     * 定时修改任务状态
     */
    @Override
    public void taskStatusTimer(String params) {
        try {
            RSet<String> set = RedisUtil.getRedisClient().getSet(PreDealServiceImpl.HAOBAN_TASK_ID_SET_CACHE);
            logger.info("好办任务状态开始={},{}",set.size(),set);
            Iterator<String> it = set.iterator() ;
            while(it.hasNext()) {
                String taskId = it.next();
                TabHaobanSyncTask task = syncTaskService.getSyncTask(taskId);
                if(null == task) {
                    logger.info("任务不存在taskId={}",taskId);
                    it.remove();
                    continue;
                }
                if(task.getCreateTime().getTime()+1000*60*60*24< System.currentTimeMillis()) {
                    logger.info("超过一天taskId={}",taskId);
                    it.remove();
                    continue;
                }
                if(task.getTaskType()==SyncTaskTypeEnum.FRIEND_WX_ENTEPRISE.getType()
                        || task.getTaskType()==SyncTaskTypeEnum.FRIEND_SINGLE.getType() || task.getTaskType()==SyncTaskTypeEnum.FRIEND_STORE.getType()) {
                   boolean flag = this.updateTaskStatus(taskId);
                   if(flag) {
                       it.remove();
                   }
                }
            }
            logger.info("好办任务状态完成={}",set);
        }catch(Exception e) {
            logger.warn(e.toString(),e);
        }
    }

    @Override
    public void staffTaskStatusTimer(String params) {
        try {
            RSet<String> set = RedisUtil.getRedisClient().getSet(PreDealServiceImpl.HAOBAN_TASK_STAFF_ID_SET_CACHE);
            logger.info("好办任务状态开始staff={},{}",set.size(),set);
            Iterator<String> it = set.iterator() ;
            while(it.hasNext()) {
                String v = it.next() ;
                String[] arr = v.split("#") ;
                if(arr.length != 3) {
                    logger.info("异常{},{}",v );
                    it.remove();
                    continue;
                }
                String taskId = arr[0] ;
                String staffId = arr[1] ;
                int type = Integer.valueOf(arr[2]) ;
                TabHaobanSyncTask task = syncTaskService.getSyncTask(taskId);
                if(null == task) {
                    logger.info("任务不存在taskId={}",taskId);
                    it.remove();
                    continue;
                }
                if(task.getCreateTime().getTime()+1000*60*60*24< System.currentTimeMillis()) {
                    logger.info("超过一天taskId={},{}",taskId,staffId);
                    it.remove();
                    continue;
                }
                boolean flag = this.updateStaffTaskStatus(taskId,staffId,type) ;
                if(flag) {
                    it.remove();
                }
            }
            logger.info("好办任务状态完成staff={}",set);
        }catch(Exception e) {
            logger.warn(e.toString(),e);
        }
    }

    @Override
    public void taskSyncStaffTimer(String params) {
        try {
            RSet<String> set = RedisUtil.getRedisClient().getSet(PreDealServiceImpl.HAOBAN_TASK_DEPART_SET_CACHE);
            logger.info("通讯录同步定时开始size={},{}",set.size(),set);
            Iterator<String> it = set.iterator() ;
            while(it.hasNext()) {
                String v = it.next() ;
                String[] arr = v.split("#") ;
                if(arr.length != 2) {
                    logger.info("异常{},{}",v );
                    it.remove();
                    continue;
                }
                String taskId = arr[0] ;
                int type = Integer.valueOf(arr[1]) ;
                TabHaobanSyncTask task = syncTaskService.getSyncTask(taskId);
                if(null == task) {
                    logger.info("任务不存在taskId={}",taskId);
                    it.remove();
                    continue;
                }
                if(task.getStatusFlag() != 4) {
                    this.syncTaskService.updateTaskStatus(taskId,4) ;
                }
                if(task.getCreateTime().getTime()+1000*60*60*3< System.currentTimeMillis()) {
                    logger.info("超过3小时taskId={}",taskId);
                    it.remove();
                    RedisUtil.delLocalCache("department-list-cache-" + task.getWxEnterpriseId());
                    continue;
                }
                boolean flag = this.syncDepartmentStaffTask(taskId,type) ;
                if(flag) {
                    it.remove();
                }
            }
            logger.info("通讯录同步定时完成={}",set);
        }catch(Exception e) {
            logger.warn(e.toString(),e);
        }
    }

    private boolean syncDepartmentStaffTask(String taskId,int type) {
        boolean flag = preDealService.checkTask(taskId, type);
        if (!flag) {
            logger.info("同步通讯录部门还未完成={}",taskId);
            return false;
        }
        if(type==0) {
            this.syncTaskService.updateTaskStatus(taskId,4) ;
            logger.info("部门成功,开始同步成员:{}", taskId);
            String key = "haoban_sync_department_task_" + taskId;
            RedisUtil.lock(key, 3L);
            // 部门和成员拉取成功后,直接任务完成
            List<TabHaobanPreDealLog> dealLogs = preDealService.listByTaskId(taskId, PreDealTypeEnum.clerk.getVal(), PreDealStatusEnum.pre.getVal());
            if (CollectionUtils.isNotEmpty(dealLogs)) {
                Set<String> dataIds = dealLogs.stream().map(TabHaobanPreDealLog::getDataId).collect(Collectors.toSet());
                this.sendToMq(taskId, dataIds, SyncTaskStatusEnum.clerk_sync,"departmentSyncDealMq2");
            }
            RedisUtil.unlock(key);
        }else if(type==2) {
            logger.info("企微通讯录成员成功:{}", taskId);
            String key = "haoban_sync_clerk_task_" + taskId;
            RedisUtil.lock(key, 3L);
            TabHaobanSyncTask syncTask = syncTaskService.getSyncTask(taskId);
            String wxEnterpriseId = syncTask.getWxEnterpriseId();
            this.unlockTask(wxEnterpriseId) ;
            this.cleanDiffrence(wxEnterpriseId, taskId);
            logger.info("同步通讯录完成");
            String conectkey = "get_follow_user_list:"+wxEnterpriseId ;
            RedisUtil.delCache(conectkey) ;
            RedisUtil.unlock(key);
        }
        return true ;
    }

    private boolean updateTaskStatus(String taskId) {
        boolean b = preDealService.checkFriendTask(taskId, PreDealTypeEnum.friend_clerk.getVal());
        if (!b) {
            logger.info("更新task状态,还未完成={}",taskId);
            return false;
        }
        logger.info("整个task完成={}", taskId);
        this.syncTaskService.updateTaskStatus(taskId, SyncTaskStatusEnum.compute.getVal());
        return true ;
    }

    private boolean updateStaffTaskStatus(String taskId ,String stffId , int type) {
        boolean b = preDealService.checkFriendTaskByPDataId(taskId, stffId, type);
        if (!b) {
            return false;
        }
        if(type == 7) {
            logger.info("代开发完成,开始第三方好友：{},{}", taskId, stffId);
            String key = "haoban_sync_self_friend_task_" + taskId + ":" + stffId;
            String lockKey = "haoban_sync_self_friend_task_lock_" + taskId + ":" + stffId;
            RedisUtil.lock(lockKey, 3L);
            Object hasDealCheck = RedisUtil.getCache(key);
            if (hasDealCheck != null) {
                RedisUtil.unlock(lockKey);
                return false;
            }
            RedisUtil.setCache(key, stffId, 30L, TimeUnit.SECONDS);
            List<String> dataIds = preDealService.listReDataIdByPDataId(taskId, stffId, PreDealTypeEnum.friend.getVal());
            if (CollectionUtils.isEmpty(dataIds)) {
                logger.info("无第三方的数据/自建");
                String staffLockKey = DealSyncOperationApiServiceImpl.FRIEND_LOCK + stffId;
                RedisUtil.delCache(staffLockKey);
                preDealService.updateStatusByDataId(taskId, stffId, PreDealTypeEnum.friend_clerk.getVal(), PreDealStatusEnum.computed.getVal(), "成功");
            } else {
                sendToMq(taskId, new HashSet<>(dataIds), SyncTaskStatusEnum.friend_sync,null);
            }
            RedisUtil.unlock(lockKey);
        }
        if(type == 8) {
            String staffLockKey = DealSyncOperationApiServiceImpl.FRIEND_LOCK + stffId;
            RedisUtil.delCache(staffLockKey);
            logger.info("第三方好友结束：{},{},{}", taskId, stffId,staffLockKey);
            String key = "haoban_sync_third_friend_task_" + taskId + ":" + stffId;
            String lockKey = "haoban_sync_third_friend_task_lock_" + taskId + ":" + stffId;
            RedisUtil.lock(lockKey, 3L);
            Object hasDealCheck = RedisUtil.getCache(key);
            if (hasDealCheck != null) {
                RedisUtil.unlock(lockKey);
                return false;
            }
            RedisUtil.setCache(key, stffId, 30L, TimeUnit.SECONDS);
            this.preDealService.updateStatusByDataId(taskId, stffId, PreDealTypeEnum.friend_clerk.getVal(), PreDealStatusEnum.computed.getVal(), "成功");
            RedisUtil.unlock(lockKey);
        }
        return true ;
    }

}
