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

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.gic.haoban.manage.api.service.DealSyncOperationApiService;
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 com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.BasePageInfo;
import com.gic.api.base.commons.Page;
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.GICMQClientUtil;
import com.gic.commons.util.ToolUtil;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.common.utils.EntityUtil;
import com.gic.haoban.common.utils.PageUtil;
import com.gic.haoban.manage.api.dto.DealParamMqDTO;
import com.gic.haoban.manage.api.dto.hm.HmBatchModifyResultDTO;
import com.gic.haoban.manage.api.dto.qdto.hm.HmBatchModifyQDTO;
import com.gic.haoban.manage.api.dto.qdto.hm.HmClerkRelationQDTO;
import com.gic.haoban.manage.api.enums.PreDealTypeEnum;
import com.gic.haoban.manage.api.enums.SyncTaskStatusEnum;
import com.gic.haoban.manage.api.enums.SyncTaskTypeEnum;
import com.gic.haoban.manage.service.dao.mapper.hm.TabHaobanHmClerkRelationMapper;
import com.gic.haoban.manage.service.dao.mapper.hm.TabHaobanHmQrcodeMapper;
import com.gic.haoban.manage.service.entity.TabHaobanPreDealLog;
import com.gic.haoban.manage.service.entity.TabHaobanSyncTask;
import com.gic.haoban.manage.service.entity.hm.TabHaobanHmClerkRelation;
import com.gic.haoban.manage.service.entity.hm.TabHaobanHmQrcode;
import com.gic.haoban.manage.service.pojo.bo.hm.HmClerkRelationBO;
import com.gic.haoban.manage.service.service.PreDealService;
import com.gic.haoban.manage.service.service.SyncTaskService;
import com.gic.haoban.manage.service.service.hm.HmClerkRelationService;
import com.gic.haoban.manage.service.task.hm.QwHmOperation;
import com.gic.mq.sdk.GicMQClient;
import com.gic.redis.data.util.RedisUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

/**
 * 多人活码(TabHaobanHmClerkRelation)表服务实现类
 *
 * @author mozhu
 * @since 2022-07-04 15:42:20
 */
@Service
public class HmClerkRelationServiceImpl implements HmClerkRelationService {

    private static final Logger log = LoggerFactory.getLogger(HmClerkRelationService.class);
    @Autowired
    private TabHaobanHmClerkRelationMapper tabHaobanHmClerkRelationMapper;
    @Autowired
    private TabHaobanHmQrcodeMapper hmQrcodeMapper;
    @Autowired
    private ClerkService clerkService ;
    @Autowired
    private StoreService storeService ;
    @Autowired
    private SyncTaskService syncTaskService;
    @Autowired
    private PreDealService preDealService;
    @Autowired
    private DealSyncOperationApiService dealSyncOperationApiService ;


    @Override
    public int insert(HmClerkRelationQDTO hmClerkRelationQDTO) {
        hmClerkRelationQDTO.setStatus(1);
        hmClerkRelationQDTO.setCreateTime(new Date());
        hmClerkRelationQDTO.setUpdateTime(new Date());
        hmClerkRelationQDTO.setOverFlag(0);
        hmClerkRelationQDTO.setAddNum(0);
        return this.tabHaobanHmClerkRelationMapper.insert(EntityUtil.changeEntityByOrika(TabHaobanHmClerkRelation.class, hmClerkRelationQDTO));
    }

    @Override
    public HmClerkRelationBO queryByHmIdAndClerkId(Long hmId, String clerkId) {
        return EntityUtil.changeEntityByOrika(HmClerkRelationBO.class,tabHaobanHmClerkRelationMapper.queryByHmIdAndClerkId(hmId,clerkId));
    }

    @Override
    public int updateAddNumById(Long relationId, Integer overFlag) {
        return tabHaobanHmClerkRelationMapper.updateAddNumById(relationId,overFlag);
    }

    @Override
    public void resetAddNumAndOverFlag() {
        tabHaobanHmClerkRelationMapper.resetAddNumAndOverFlag();
    }

    @Override
    public List<HmClerkRelationBO> queryByClerkId(String clerkId, String enterpriseId) {
        return EntityUtil.changeEntityListByJSON(HmClerkRelationBO.class,tabHaobanHmClerkRelationMapper.queryByClerkId(clerkId,enterpriseId));
    }

    @Override
    public List<String> getClerkIdByHmId(Long hmId) {
        return tabHaobanHmClerkRelationMapper.getNumByHmId(hmId);
    }

    @Override
    public List<HmClerkRelationBO> getHmClerkByHmId(Long hmId) {
        return EntityUtil.changeEntityListByJSON(HmClerkRelationBO.class,tabHaobanHmClerkRelationMapper.getHmClerkByHmId(hmId));
    }

    @Override
    public Page<HmClerkRelationBO> getHmClerkByHmId(BasePageInfo basePageInfo, Long hmId) {
        PageHelper.startPage(basePageInfo.getPageNum(),basePageInfo.getPageSize());
        List<TabHaobanHmClerkRelation> hmClerkByHmId = tabHaobanHmClerkRelationMapper.getHmClerkByHmId(hmId);
        return PageUtil.changePageHelperToCurrentPage(new PageInfo<>(hmClerkByHmId), HmClerkRelationBO.class);
    }

    @Override
    public HmClerkRelationBO getHmClerkByHmIdAndStaffId(Long hmId, String staffId) {
        return EntityUtil.changeEntityByOrika(HmClerkRelationBO.class,tabHaobanHmClerkRelationMapper.getHmClerkByHmIdAndStaffId(hmId,staffId));
    }

    @Override
    public int updateStatusById(Integer status, Long relationId) {
        return tabHaobanHmClerkRelationMapper.updateStatusById(status,relationId);
    }

    @Override
    public List<HmClerkRelationBO> queryByHmIdNotInClerkIds(Long hmId, List<String> clerkIds) {
        return EntityUtil.changeEntityListByOrika(HmClerkRelationBO.class,tabHaobanHmClerkRelationMapper.queryByHmIdNotInClerkIds(hmId,clerkIds));
    }
    
    @Override
    public void updateByClerkChangeStore(String enterpriseId,String oldClerkId,String newClerkId) {
        ClerkDTO newClerk = this.clerkService.getclerkById(newClerkId) ;
        String clerkCode = newClerk.getClerkCode();
        String clerkName = newClerk.getClerkName() ;
        String storeId = newClerk.getStoreId();
        StoreDTO newStore = this.storeService.getStore(storeId) ;
        String storeCode = newStore.getStoreCode();
        String storeName = newStore.getStoreName() ;
        this.tabHaobanHmClerkRelationMapper.updateByClerkChangeStore(enterpriseId,newClerkId,clerkCode,clerkName,storeId, storeCode,storeName, oldClerkId) ;
    }
    
    @Override
    public ServiceResponse<List<HmBatchModifyResultDTO>> batchModify(HmBatchModifyQDTO qdto) {
        String wxEnterpriseId = qdto.getWxEnterpriseId() ;
        String enterpriseId = qdto.getEnterpriseId() ;
        String cacheKey = QwHmOperation.hmCachKey+wxEnterpriseId+enterpriseId ;
        if(null != RedisUtil.getCache(cacheKey)) {
            return ServiceResponse.failure("9999", "已有任务在执行,请稍后在处理") ;
        }
        int maxCount = 100 ;
        if("fb40256db41142a196b21ccf03e58507".equals(wxEnterpriseId)) {
            maxCount = 3 ;
        }
        List<Long> hmIdList = qdto.getHmIdList() ;
        List<TabHaobanHmClerkRelation> list = this.tabHaobanHmClerkRelationMapper.listHmClerkByHmIdList(hmIdList) ;
        log.info("查询活码关联导购数={},活码数={}",list.size(),hmIdList.size());
        Map<Long,List<TabHaobanHmClerkRelation>> map = list.stream().collect(Collectors.groupingBy(TabHaobanHmClerkRelation::getHmId));
        Map<Long , Set<String>> modifyMap = new HashMap<>();
        List<HmBatchModifyResultDTO> errList = new ArrayList<>() ;
        for(Long hmId : hmIdList) {
            List<TabHaobanHmClerkRelation> staffRelationList =  map.get(hmId) ;
            if (CollectionUtils.isEmpty(staffRelationList)) {
                log.info("活码无关联导购={}",hmId);
                HmBatchModifyResultDTO err = new HmBatchModifyResultDTO(hmId,3,"无关联导购") ;
                errList.add(err) ;
                continue;
            }
            Set<String> clerkIdSet = staffRelationList.stream().map(o->o.getClerkId()).collect(Collectors.toSet()) ;
            if(CollectionUtils.isNotEmpty(staffRelationList)) {
                Set<String> clerkIdSetBak = new HashSet<>();
                clerkIdSetBak.addAll(clerkIdSet) ;
                List<String> modifyIdList = qdto.getClerkIdList();
                // add
                if(qdto.getOptType()==1) {
                    clerkIdSetBak.addAll(modifyIdList) ;
                    if(clerkIdSetBak.size()>maxCount) {
                        HmBatchModifyResultDTO err = new HmBatchModifyResultDTO(hmId,1,"超出多人活码成员数上限,最多支持添加100个成员") ;
                        errList.add(err) ;
                    }
                }
                // 减
                if(qdto.getOptType()==2) {
                    clerkIdSetBak.removeAll(modifyIdList);
                    if(clerkIdSetBak.size()<=0) {
                        HmBatchModifyResultDTO err = new HmBatchModifyResultDTO(hmId,2,"成员数为0") ;
                        errList.add(err) ;
                    }
                }
                log.info("hm={},修改前={},修改后={}",hmId,clerkIdSet.size(),clerkIdSetBak.size());
                //  1 继续执行更新 2不废弃活码
                if(qdto.getUpdateType()==2 && clerkIdSetBak.size()==0) {
                    log.info("无人活码={}",hmId);
                    continue ;
                }
                if(qdto.getOptType()==1 && clerkIdSetBak.size()>maxCount) {
                    log.info("超人数活码={}",hmId);
                    continue ;
                }
                if(clerkIdSetBak.size() != clerkIdSet.size()) {
                    modifyMap.put(hmId, clerkIdSetBak) ;
                }
            }
        }
        log.info("异常的活码={}",JSONObject.toJSONString(errList));
        if(CollectionUtils.isNotEmpty(errList) && qdto.getUpdateType()==0) {
            List<Long> hmidList = errList.stream().map(o->o.getHmid()).collect(Collectors.toList()) ;
            List<TabHaobanHmQrcode> qrcodeList =  this.hmQrcodeMapper.queryByIdList(hmidList) ;
            Map<Long,TabHaobanHmQrcode> qrcodeMap = qrcodeList.stream().collect(Collectors.toMap(TabHaobanHmQrcode::getHmId, o->o)) ;
            errList.forEach(o->{
                if(null != qrcodeMap.get(o.getHmid())) {
                    o.setHmCode(qrcodeMap.get(o.getHmid()).getHmCode());
                    o.setHmName(qrcodeMap.get(o.getHmid()).getName());
                }
            });
            return ServiceResponse.success(errList) ;
        }
        if(modifyMap.size()==0) {
            return ServiceResponse.failure("9999", "没有需要处理的活码") ;
        }
        String lockKey = cacheKey+"lock";
        if(RedisUtil.isLocked(lockKey) || null != RedisUtil.getCache(cacheKey)) {
            return ServiceResponse.failure("9999", "已有任务在执行,请稍后在处理") ;
        }
        RedisUtil.lock(lockKey, 2L);
        if(null != RedisUtil.getCache(cacheKey)) {
            return ServiceResponse.failure("9999", "已有任务在执行,请稍后在处理") ;
        }
        RedisUtil.setCache(cacheKey,"1") ;
        RedisUtil.unlock(lockKey);
        String clerkId = qdto.getOptClerkId() ;
        String name = qdto.getOptName() ;
        String taskName = "批量修改多人活码";
        String taskId = this.createModifyHmTask(wxEnterpriseId, taskName, clerkId,
                name, SyncTaskTypeEnum.BATCH_MODIFY_HM.getType());
        if (StringUtils.isBlank(taskId)) {
            RedisUtil.delCache(cacheKey) ;
            return ServiceResponse.failure("9999", "创建任务失败") ;
        }
        if(CollectionUtils.isNotEmpty(errList)) {
            List<TabHaobanPreDealLog> dealLogList = new ArrayList<>() ;
            for(HmBatchModifyResultDTO err : errList) {
                if(err.getErrcode()==1 || err.getErrcode()==3) {
                    Long hmid = err.getHmid() ;
                    TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
                    dealLog.setEnterpriseId(enterpriseId);
                    dealLog.setWxEnterpriseId(wxEnterpriseId);
                    dealLog.setTaskId(taskId);
                    dealLog.setDataId(hmid+"") ;
                    dealLog.setpDataId(hmid+"");
                    dealLog.setDataContent(null);
                    dealLog.setDataType(PreDealTypeEnum.modify_hm.getVal());
                    dealLog.setStatusFlag(3);
                    dealLog.setReason(err.getMessage());
                    dealLogList.add(dealLog) ;
                }
            }
            if(CollectionUtils.isNotEmpty(dealLogList)) {
                this.preDealService.insert(dealLogList);
            }
        }

        log.info("总任务数={},taskid={}",modifyMap.size(),taskId);
        List<TabHaobanPreDealLog> dealLogList = modifyMap.keySet().stream().map(hmid -> {
            TabHaobanPreDealLog dealLog = new TabHaobanPreDealLog();
            dealLog.setEnterpriseId(enterpriseId);
            dealLog.setWxEnterpriseId(wxEnterpriseId);
            dealLog.setTaskId(taskId);
            dealLog.setDataId(hmid+"") ;
            dealLog.setpDataId(hmid+"");
            dealLog.setDataContent(JSON.toJSONString(modifyMap.get(hmid)));
            dealLog.setDataType(PreDealTypeEnum.modify_hm.getVal());
            dealLog.setStatusFlag(0);
            return dealLog;
        }).collect(Collectors.toList());
        this.preDealService.insert(dealLogList);
        this.dealSyncOperationApiService.sendToMq(taskId, dealLogList.stream().map(o->o.getDataId()).collect(Collectors.toSet()), SyncTaskStatusEnum.modify_hm,"departmentSyncDealMq2");
        ServiceResponse resp = ServiceResponse.success() ;
        resp.setMessage(taskId);
        return resp ;
    }


    public String createModifyHmTask(String wxEnterpriseId, String taskName, String staffId, String staffName, int syncTaskType) {
        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);
        return tabHaobanSyncTask.getTaskId();
    }
}
