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

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import com.gic.enterprise.api.dto.EnterpriseDTO;
import com.gic.enterprise.api.service.EnterpriseService;
import com.gic.haoban.manage.api.dto.CommonMQDTO;
import com.gic.haoban.manage.api.dto.ContentMaterialDTO;
import com.gic.haoban.manage.api.dto.StaffClerkRelationDTO;
import com.gic.haoban.manage.api.dto.chat.*;
import com.gic.haoban.manage.api.dto.qdto.chat.GroupChatSearchQDTO;
import com.gic.haoban.manage.api.dto.qdto.chat.OwnerSearchQDTO;
import com.gic.haoban.manage.api.enums.NoticeMessageTypeEnum;
import com.gic.haoban.manage.api.qdto.StaffSendResultQDTO;
import com.gic.haoban.manage.api.service.HaobanCommonMQApiService;
import com.gic.haoban.manage.api.service.WxEnterpriseRelatedApiService;
import com.gic.haoban.manage.api.util.notify.NoticeMessageUtil;
import com.gic.haoban.manage.service.dao.mapper.TabHaobanStaffClerkRelationMapper;
import com.gic.haoban.manage.service.dao.mapper.WxEnterpriseRelatedMapper;
import com.gic.haoban.manage.service.dao.mapper.chat.*;
import com.gic.haoban.manage.service.dao.mapper.moment.QwMomentPlanAttendMapper;
import com.gic.haoban.manage.service.service.StaffClerkRelationService;
import com.gic.haoban.manage.service.service.content.impl.GroupMessageServiceImpl;
import com.gic.haoban.manage.service.util.StreamUtils;
import com.gic.haoban.task.api.dto.TaskSettingDTO;
import com.gic.haoban.task.api.service.SettingApiService;
import com.gic.haoban.task.manage.api.service.QywxGroupSendCanvasApiService;
import com.gic.thirdparty.cloudfile.CloudFileUtil;
import com.gic.thirdparty.cloudfile.enums.CloudFileBusinessOptEnum;
import com.gic.thirdparty.cloudfile.enums.CloudFileTypeEnum;
import com.gic.thirdparty.cloudfile.pojo.CloudFileInfo;
import com.gic.wechat.api.dto.qdto.group.QywxGroupMessageQDTO;
import com.gic.wechat.api.dto.qywx.group.QywxGroupMessageInfoDTO;
import com.gic.wechat.api.dto.qywx.group.QywxGroupMsgResp;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.BasePageInfo;
import com.gic.api.base.commons.JSONResponse;
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.DateUtil;
import com.gic.commons.util.EntityUtil;
import com.gic.commons.util.GICMQClientUtil;
import com.gic.commons.util.PageHelperUtils;
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.manage.api.dto.WxEnterpriseQwDTO;
import com.gic.haoban.manage.api.dto.qdto.chat.GroupChatPlanSearchQDTO;
import com.gic.haoban.manage.api.enums.PendingTaskTypeEnum;
import com.gic.haoban.manage.api.enums.chat.PlanSendStatusEnum;
import com.gic.haoban.manage.service.config.Config;
import com.gic.haoban.manage.service.dao.mapper.StaffMapper;
import com.gic.haoban.manage.service.entity.TabHaobanStaff;
import com.gic.haoban.manage.service.entity.chat.TabGroupChatPlan;
import com.gic.haoban.manage.service.entity.chat.TabGroupChatPlanLog;
import com.gic.haoban.manage.service.entity.chat.TabGroupChatPlanOwnerLog;
import com.gic.haoban.manage.service.pojo.bo.PendingTaskBO;
import com.gic.haoban.manage.service.pojo.bo.chat.GroupChatBO;
import com.gic.haoban.manage.service.pojo.bo.chat.GroupChatPlanBO;
import com.gic.haoban.manage.service.service.QywxSendService;
import com.gic.haoban.manage.service.service.WxEnterpriseService;
import com.gic.haoban.manage.service.service.chat.GroupChatPlanOwnerLogService;
import com.gic.haoban.manage.service.service.chat.GroupChatPlanService;
import com.gic.haoban.manage.service.service.chat.GroupChatService;
import com.gic.haoban.manage.service.service.notify.PendingTaskService;
import com.gic.mq.sdk.GicMQClient;
import com.gic.quartz.api.dto.QuartzTaskDTO;
import com.gic.quartz.api.service.QuartzService;
import com.gic.wechat.api.dto.qywx.QywxSendMessageResultDTO;
import com.gic.wechat.api.service.qywx.QywxSuiteApiService;
import com.github.pagehelper.PageHelper;

@Service("groupChatPlanService")
public class GroupChatPlanServiceImpl implements GroupChatPlanService {

    private static org.apache.logging.log4j.Logger logger = LogManager.getLogger(GroupChatPlanService.class);

    private final ExecutorService executorService = Executors.newFixedThreadPool(5);

    @Autowired
    private GroupChatPlanMapper groupChatPlanMapper;
    @Autowired
    private GroupChatPlanOwnerLogService groupChatPlanOwnerLogService;
    @Autowired
    private GroupChatPlanOwnerLogMapper groupChatPlanOwnerLogMapper;
    @Autowired
    private GroupChatPlanLogMapper groupChatPlanLogMapper;
    @Autowired
    private QywxSendService qywxSendService;
    @Autowired
    private WxEnterpriseService wxEnterpriseService;
    @Autowired
    private Config config;
    @Autowired
    private QywxSuiteApiService qywxSuiteApiService;
    @Autowired
    private StaffMapper staffMapper;
    @Autowired
    private GroupChatService groupChatService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private QuartzService quartzService;
    @Autowired
    private PendingTaskService pendingTaskService;
    @Autowired
    private EnterpriseService enterpriseService;
    @Autowired
    private GroupChatOwnerMapper groupChatOwnerMapper ;
    @Autowired
    private TabHaobanStaffClerkRelationMapper tabHaobanStaffClerkRelationMapper ;
    @Autowired
    private GroupChatMapper groupChatMapper ;
    @Autowired
    private HaobanCommonMQApiService haobanCommonMQApiService ;
    @Autowired
    private QywxGroupSendCanvasApiService qywxGroupSendCanvasApiService ;
    @Autowired
    private WxEnterpriseRelatedMapper wxEnterpriseRelatedMapper;
    @Autowired
    private StaffClerkRelationService staffClerkRelationService ;
    @Autowired
    private SettingApiService settingApiService ;
    @Autowired
    private QwMomentPlanAttendMapper qwMomentPlanAttendMapper ;

    private static GicMQClient mqClient = GICMQClientUtil.getClientInstance();

    // 每次成员数
    private int pageSize = 1000;

    // 发送队列
    private void putMQForSend(Long id) {
        try {
            mqClient.sendCommonMessage("haobanChatMQ", id + "",
                    "com.gic.haoban.manage.api.service.chat.GroupChatPlanApiService", "doPlanTimer");
        } catch (Exception e) {
            logger.error("发送MQ异常");
            logger.info("异常",e);
        }
    }

    // 统计队列
    private void putMQForData(Long id) {
        try {
            mqClient.sendCommonMessage("haobanChatMQ", id + "",
                    "com.gic.haoban.manage.api.service.chat.GroupChatPlanApiService", "doPlanSendInfoTimer");
        } catch (Exception e) {
            logger.error("发送MQ异常");
            logger.info("异常",e);
        }
    }

    @Override
    public void save(GroupChatPlanDTO dto) {
        Long planId = dto.getPlanId();
        TabGroupChatPlan entity = EntityUtil.changeEntityByJSON(TabGroupChatPlan.class, dto);
        if (entity.getSendType() == 1) {
            entity.setSendTime(new Date());
        }
        //处理群发素材上传生成新的url
//        String chatContent = dealContentMaterial(dto.getEnterpriseId(), entity);
//        entity.setChatContent(chatContent);
        entity.setStartTime(entity.getSendTime()); 
        Date endTime = DateUtil.addDay(entity.getStartTime(), entity.getExpireDays());
        entity.setEndTime(DateUtil.getEndTimeOfDay(endTime));
        String staffIdList = dto.getStaffIdList();
        if (null == planId) {
            planId = UniqueIdUtils.uniqueLong();
            entity.setPlanId(planId);
            entity.setStatusFlag(1);
            if(StringUtils.isNotEmpty(staffIdList)) {
                entity.setStaffCount(staffIdList.split(",").length);
            }else {
                entity.setStaffCount(0);
            }
            entity.setSendCount(0);
            entity.setSuccessChatCount(0);
            entity.setFailChatCount(0);
            this.groupChatPlanMapper.insert(entity);
        } else {
            TabGroupChatPlan old = this.groupChatPlanMapper.selectById(planId);
            int staffCount = old.getStaffCount();
            if (StringUtils.isNotBlank(dto.getDelStaffIdList())) {
                staffCount = staffCount - dto.getDelStaffIdList().split(",").length;
            }
            if (StringUtils.isNotBlank(dto.getStaffIdList())) {
                staffCount = staffCount + dto.getStaffIdList().split(",").length;
            }
            entity.setStaffCount(staffCount);
            this.groupChatPlanMapper.updateById(entity);
            // 删除本次删除的
            this.groupChatPlanOwnerLogService.deleteByStaffIds(planId, dto.getDelStaffIdList());
            if(old.getExecType() != dto.getExecType()) {
                this.groupChatPlanOwnerLogMapper.updateExecType(planId,dto.getExecType());
            }
        }
        // 新增群主日志
        this.groupChatPlanOwnerLogService.batchAdd(staffIdList, entity);
        // 立即发送
        if (entity.getSendType() == 1) {
            this.addOrDelTimer(planId, entity.getSendTime(), 0);
//            this.doPlan(planId);
            this.putMQForSend(planId);
        } else {
            this.addOrDelTimer(planId, entity.getSendTime(), 1);
        }
    }

    private String dealContentMaterial(String enterpriseId, TabGroupChatPlan chatPlan) {
        String chatContent = chatPlan.getChatContent();
        logger.info("处理群发素材上传生成新的url chatPlan:{}", JSON.toJSONString(chatPlan));
        EnterpriseDTO enterpriseDTO = enterpriseService.getEnterpriseById(enterpriseId);
        Integer materialFrom = chatPlan.getMaterialFrom();
        if (materialFrom == null || materialFrom != 2) {
            logger.info("不是内容中心素材不处理");
            return chatContent;
        }
        if (StringUtils.isBlank(chatContent)) {
            return chatContent;
        }
        List<ChatContentDTO> chatContentList = JSONArray.parseArray(chatContent, ChatContentDTO.class);
        logger.info("处理内容素材:{}", JSON.toJSONString(chatContentList));
        try {
            CountDownLatch countDownLatch = new CountDownLatch(chatContentList.size());
            for (ChatContentDTO chatContentDTO : chatContentList) {
                executorService.execute(()->{
                    //是否上传url地址
                    boolean urlChangeFlag = chatContentDTO.getUrlChangeFlag() != null && chatContentDTO.getUrlChangeFlag() == 1;
                    if (chatContentDTO.getType() != 1 || urlChangeFlag) {
                        countDownLatch.countDown();
                        return;
                    }
                    //封面
                    String img = chatContentDTO.getImg();
                    if (StringUtils.isNotBlank(img) && img.contains(".")) {
                        String fileExtension = img.substring(img.lastIndexOf(".") + 1);
                        InputStream imageStream = StreamUtils.getImageStream(img);
                        if (imageStream != null) {
                            CloudFileInfo fileInfo = CloudFileUtil.uploadFile(imageStream, fileExtension, CloudFileTypeEnum.IMAGE, enterpriseDTO.getFactoryCode(), CloudFileBusinessOptEnum.HAOBAN_COMMON);
                            chatContentDTO.setImg(fileInfo.getOrgFileUrl());
                        }
                    }
                    //内容（视频）
                    String content = chatContentDTO.getContent();
                    if (StringUtils.isNotBlank(content) && content.contains(".")) {
                        String fileExtension = content.substring(content.lastIndexOf(".") + 1);
                        InputStream videoStream = StreamUtils.getImageStream(content);
                        if (videoStream != null) {
                            CloudFileInfo fileInfo = CloudFileUtil.uploadFile(videoStream, fileExtension, getCloudFileTypeEnum(chatContentDTO.getType()), enterpriseDTO.getFactoryCode(), CloudFileBusinessOptEnum.HAOBAN_COMMON);
                            chatContentDTO.setContent(fileInfo.getOrgFileUrl());
                            chatContentDTO.setUrlChangeFlag(com.gic.api.base.commons.Constant.FLAG_TRUE);
                        }
                    }
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
        } catch (Exception e) {
            logger.error("处理内容素材异常",e);
        }
        chatContent = JSON.toJSONString(chatContentList);
        logger.info("更新内容素材:{}", chatContent);
        return chatContent;
    }

    private CloudFileTypeEnum getCloudFileTypeEnum(Integer type) {
        if (type == null) {
            return CloudFileTypeEnum.OTHER;
        }
        if (type == 2) {
            return CloudFileTypeEnum.IMAGE;
        } else if (type == 4) {
            return CloudFileTypeEnum.VIDEO;
        }
        return CloudFileTypeEnum.OTHER;
    }

    @Override
    public GroupChatPlanBO getById(Long planId) {
        TabGroupChatPlan plan = this.groupChatPlanMapper.selectById(planId);
        GroupChatPlanBO bo = EntityUtil.changeEntityByJSON(GroupChatPlanBO.class, plan);
        return bo;
    }

    @Override
    public Page<GroupChatPlanBO> listPage(GroupChatPlanSearchQDTO qdto, BasePageInfo basePageInfo) {
        if (StringUtils.isNotBlank(qdto.getSearchParams())) {
            String params = qdto.getSearchParams();
            qdto.setSearchParamsLike("%" + params + "%");
        }
        PageHelper.startPage(basePageInfo);
        List<TabGroupChatPlan> list = this.groupChatPlanMapper.list(qdto);
        Page<GroupChatPlanBO> retPage = PageHelperUtils.changePageHelperToCurrentPage(list, GroupChatPlanBO.class);
        return retPage;
    }

    private List<String> filterNoClerk(String wxEnterpriseId,List<GroupChatOwnerDTO> list) {
        Set<String> set = list.stream().map(o->o.getStaffId()).collect(Collectors.toSet());
        List<StaffClerkRelationDTO> stafIdList = this.tabHaobanStaffClerkRelationMapper.listByStaffIdsForClerk(wxEnterpriseId,set) ;
        if(CollectionUtils.isNotEmpty(stafIdList)) {
            return stafIdList.stream().map(o->o.getStaffId()).collect(Collectors.toList());
        }
        return Collections.emptyList() ;
    }

    private void sendNotice(String enterpriseId, String staffId ,String clerkId , String taskName , Date endTime,Long planId,Long ownerLogId) {
        logger.info("发送社群任务通知,clerkId={}",clerkId);
        //  发送通知
        Map<String, String> map = new HashMap<>();
        map.put("taskName", taskName);
        map.put("overTime", DateUtil.dateToStr(endTime,"yyyy-MM-dd HH:mm:ss"));
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("planId",planId) ;
        jsonObject.put("ownerLogId",ownerLogId) ;
        if(null != clerkId) {
            ClerkDTO clerk = this.clerkService.getclerkById(clerkId);
            if (null != clerk) {
                jsonObject.put("storeId", clerk.getStoreId());
            }
        }
        int messageType = NoticeMessageTypeEnum.GROUP_CHAT_PLAN.getType();
        NoticeMessageUtil.sendNoticeMessageByStaff(enterpriseId,staffId,clerkId,messageType,null,map,jsonObject);
    }

    @Override
    public void doPlan(Long planId) {
        logger.info("开始群群发发送{}", planId);
        DingUtils.send("开始群群发发送,planId=" + planId + ",tranceid=" + ProviderLocalTag.tag.get().traceId, false);
        TabGroupChatPlan plan = this.groupChatPlanMapper.selectById(planId);
        if (null == plan) {
            logger.info("计划不存在,planid={}", planId);
            return;
        }
        if (plan.getSendFlag() == PlanSendStatusEnum.SENDED.getCode()) {
            logger.info("计划已执行过,planid={}", planId);
            return;
        }
        this.groupChatPlanMapper.updateSendFlag(planId);
        String wxEnterpriseId = plan.getWxEnterpriseId();
        Integer materialFrom = plan.getMaterialFrom();
        // 企微素材id
        List<String> sendIdList = new ArrayList<>();
        // 消息文本
        String message = null;
        // 内容素材
        List<ContentMaterialDTO> materialList = new ArrayList<>();
        ContentMaterialDTO materialDTO = null;
        String chatContent = plan.getChatContent();
        if (materialFrom == null || materialFrom == 1) {
            JSONArray jsonArr = JSONArray.parseArray(chatContent);
            for (int i = 0; i < jsonArr.size(); i++) {
                JSONObject json = jsonArr.getJSONObject(i);
                sendIdList.add(json.getString("relation_id"));
            }
        }else {
            List<ChatContentDTO> contentDTOList = JSONArray.parseArray(chatContent, ChatContentDTO.class);
            for (ChatContentDTO ecmChatContent : contentDTOList) {
                Integer type = ecmChatContent.getType();
                if (type == null) {
                    continue;
                }
                if (type == 1) {
                    message = ecmChatContent.getContent();
                }else {
                    materialDTO = new ContentMaterialDTO();
                    materialDTO.setMediaType(1);
                    if (type == 2) {
                        materialDTO.setImgUrl(ecmChatContent.getImg());
                    } else if (type == 4) {
                        materialDTO.setImgUrl(ecmChatContent.getContent());
                    }
                    materialDTO.setMaterialType(ecmChatContent.getType());
                    materialList.add(materialDTO);
                }
            }
        }
        List<TabGroupChatPlanOwnerLog> ownerList = null;
        int sendAlFlag = plan.getSendAllFlag() ;
        String allSearchParams = plan.getAllSearchParams() ;
        // 发送全部群主
        if(sendAlFlag==1) {
            int ownerPageNo = 0;
            int ownerPageSize = 500 ;
            int totalCount = 0 ;
            List<GroupChatOwnerDTO> list = null;
            String searchParams = null ;
            List<String> departmentIdList = null ;
            if(StringUtils.isNotEmpty(allSearchParams)) {
                JSONObject json = JSONObject.parseObject(allSearchParams) ;
                searchParams = json.getString("searchParams") ;
                String dpid = json.getString("departmentId") ;
                if(StringUtils.isNotBlank(dpid)) {
                    departmentIdList = this.groupChatService.setDepartIdList(wxEnterpriseId,dpid) ;
                }
                if(StringUtils.isNotBlank(searchParams)) {
                    searchParams ="%" + searchParams.trim() + "%";
                }
            }
            while (true) {
                if(null != searchParams || null != departmentIdList) {
                    list = this.groupChatOwnerMapper.listOwnerPage(wxEnterpriseId, departmentIdList,searchParams,ownerPageNo * ownerPageSize, ownerPageSize);
                }else {
                    list = this.groupChatOwnerMapper.listOwnerForStatistic(wxEnterpriseId, ownerPageNo * ownerPageSize, ownerPageSize);
                }
                if (CollectionUtils.isEmpty(list)) {
                    break;
                }
                ownerPageNo++;
                logger.info("全部,群主数={},{},过滤后={}", wxEnterpriseId,list.size());
                String staffIds = list.stream().map(o->o.getStaffId()).collect(Collectors.joining(",")) ;
                totalCount = totalCount + list.size() ;
                this.groupChatPlanOwnerLogService.batchAdd(staffIds, plan);
            }
            this.groupChatPlanMapper.updateStaffCount(planId,totalCount);
        }
        int pageNum = 0;
        if(plan.getExecType() == 1) {
            logger.info("好办小程序执行={}",planId);
            while (true) {
                ownerList = this.groupChatPlanOwnerLogMapper.listForDoPlan(planId, pageNum * pageSize, pageSize);
                if (CollectionUtils.isEmpty(ownerList)) {
                    break;
                }
                pageNum++;
                for (TabGroupChatPlanOwnerLog ownerLog : ownerList) {
                   boolean flag = this.groupChatPlanOwnerLogService.update(ownerLog);
                   if(flag) {
                       // 发送消息
                       String enterpriseId = ownerLog.getEnterpriseId() ;
                       String clerkId = ownerLog.getClerkId() ;
                       String staffId = ownerLog.getStaffId() ;
                       this.sendNotice(enterpriseId,staffId,clerkId,plan.getName(),plan.getEndTime(),planId,ownerLog.getOwnerLogId());
                   }
                }
            }
            return;
        }
        while (true) {
            ownerList = this.groupChatPlanOwnerLogMapper.listForDoPlan(planId, pageNum * pageSize, pageSize);
            if (CollectionUtils.isEmpty(ownerList)) {
                break;
            }
            pageNum++;
            for (TabGroupChatPlanOwnerLog ownerLog : ownerList) {
                try {
                    ServiceResponse<String> sendResp;
                    String staffId = ownerLog.getStaffId();
                    if (plan.getMaterialFrom() == null || plan.getMaterialFrom() == 1) {
                        sendResp = qywxSendService.sendChatMessage(wxEnterpriseId, staffId,
                                sendIdList,2,planId+"");
                    }else {
                        sendResp = qywxSendService.sendChatMessage(wxEnterpriseId, staffId,
                                materialList,message);
                    }
                    logger.info("sendResp={}",JSON.toJSONString(sendResp));
                    if (sendResp.isSuccess()) {
                        String msgid = sendResp.getResult();
                        ownerLog.setMsgid(msgid);
                        ownerLog.setSendStatus(PlanSendStatusEnum.TO_BE_SEND.getCode());
                    } else {
                        ownerLog.setRemark(sendResp.getMessage().substring(0, 500));
                        ownerLog.setSendStatus(PlanSendStatusEnum.FAIL.getCode());
                    }
                    ownerLog.setWxEnterpriseId(wxEnterpriseId);
                    this.groupChatPlanOwnerLogService.update(ownerLog);
                    // 代办
                    if (ownerLog.getSendStatus() == PlanSendStatusEnum.TO_BE_SEND.getCode()
                            && StringUtils.isNotBlank(ownerLog.getClerkId())
                            && StringUtils.isNotBlank(ownerLog.getMsgid())) {
                        this.savePendTask(ownerLog, plan);
                    }
                } catch (Exception e) {
                    logger.info("群群发任务异常,ownerLog={},{}", ownerLog.getOwnerLogId(),e.getMessage());
                }
            }
        }
    }

    private void savePendTask(TabGroupChatPlanOwnerLog ownerLog, TabGroupChatPlan plan) {
        logger.info("创建导购待办={}", JSON.toJSONString(ownerLog));
        PendingTaskBO task = new PendingTaskBO();
        task.setRelationId(ownerLog.getOwnerLogId() + "");
        task.setBusinessId(ownerLog.getPlanId() + "");
        task.setTaskType(PendingTaskTypeEnum.GROUP_CHAT.getType());
        task.setTitle(plan.getName());
        task.setInvalidTime(plan.getEndTime());
        task.setDescription(plan.getRemark());
        task.setStoreId(ownerLog.getStoreId());
        task.setClerkId(ownerLog.getClerkId());
        task.setEnterpriseId(ownerLog.getEnterpriseId());
        task.setOverdueTime(plan.getEndTime());
        this.pendingTaskService.addOrUpdatePendingTask(task);
    }

    @Override
    public void doPlanSendInfoTimer(String params) {
        DingUtils.send("开始群群发统计(定时),params=" + params + ",tranceid=" + ProviderLocalTag.tag.get().traceId, false);
        Long planId = Long.parseLong(params);
        List<Long> idList = this.groupChatPlanOwnerLogService.listForTimer(planId);
        logger.info("定时处理群发结果,条数={}", idList.size());
        for (Long ownerLogId : idList) {
            try {
                this.doPlanSendInfo(ownerLogId);
            } catch (Exception e) {
                logger.info("异常",e);
            }
        }
    }

    @Override
    public void doPlanSendInfo(Long ownerLogId) {
        logger.info("开始群群发统计{}", ownerLogId);
        TabGroupChatPlanOwnerLog ownerLog = this.groupChatPlanOwnerLogService.getById(ownerLogId);
        if (ownerLog.getSendStatus() == 2 && null != ownerLog.getSendTime() && ownerLog.getSendTime().getTime() < System.currentTimeMillis()-1000*60*60*12) {
            logger.info("已统计过");
            return;
        }
        logger.info("开始群群发统计{}", ownerLog.getMsgid());
        if(StringUtils.isBlank(ownerLog.getMsgid())) {
            logger.info("msgid为空");
            return ;
        }
        Long planId = ownerLog.getPlanId();
        TabGroupChatPlan plan = this.groupChatPlanMapper.selectById(planId);
        if (null == plan) {
            logger.info("计划不存在{}", planId);
            return;
        }
        if(null != ownerLog.getDataGetTime()) {
            logger.info("已统计过");
            return;
        }
        String wxEnterpriseId = ownerLog.getWxEnterpriseId();
        String enterpriseId = ownerLog.getEnterpriseId();
        String msgid = ownerLog.getMsgid();
        String staffId = ownerLog.getStaffId();
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
        TabHaobanStaff staff = this.staffMapper.selectByPrimaryKey(staffId);
        if (null == staff) {
            logger.info("成员不存在{}", staffId);
            return;
        }
        String userid = staff.getWxUserId();
        if (qwDTO.needOpenUserId3th()) {
            userid = staff.getWxOpenUseId();
        }
        JSONResponse respon = null ;
        if(qwDTO.isSelf()) {
            respon = qywxSuiteApiService.resultExternalMessageSelf(qwDTO.getThirdCorpid(), qwDTO.getSelfSecret(),
                    msgid, null, userid , qwDTO.getUrlHost());
        }else {
            respon = qywxSuiteApiService.resultExternalMessage(qwDTO.getThirdCorpid(), config.getWxSuiteid(),
                    msgid, null, userid);
        }
        logger.info("统计企微返回={}", JSON.toJSONString(respon));
        if (respon.getErrorCode() != 0) {
            return;
        }
        List<QywxSendMessageResultDTO> list = (List<QywxSendMessageResultDTO>) respon.getList();
        if (CollectionUtils.isEmpty(list)) {
            logger.info("企微返回列表空");
            return;
        }
        int sendCount = 0;
        int failCount = 0;
        List<TabGroupChatPlanLog> addList = new ArrayList<>();
        boolean endFlag = false;
        List<Long> doneGroupChatIdList = new ArrayList<>() ;
        Date sendTime = null ;
        for (QywxSendMessageResultDTO item : list) {
            TabGroupChatPlanLog entity = new TabGroupChatPlanLog();
            sendTime = item.getSendTime();
            if(null == sendTime) {
                continue;
            }
            String wxChatId = item.getChatId();
            // 如果企微的发送时间晚于计划的结束时间,不记录此类数据
            if (sendTime.after(plan.getEndTime())) {
                logger.info("发送时间晚计划结束");
                endFlag = true;
                continue;
            }
            GroupChatBO chat = this.groupChatService.getByWxChatId(wxEnterpriseId, wxChatId);
            if (null == chat || StringUtils.isBlank(chat.getEnterpriseId())) {
                logger.info("群不存在,或未认领,wxChatId={}", wxChatId);
                continue;
            }
            if (!chat.getEnterpriseId().equals(plan.getEnterpriseId())) {
                logger.info("群的商户id和计划的商户id不一致{},{}", chat.getEnterpriseId(), plan.getEnterpriseId());
                continue;
            }
            entity.setGroupChatId(chat.getGroupChatId());
            doneGroupChatIdList.add(chat.getGroupChatId()) ;
            // 企微返回成功
            // 0-未发送 1-已发送 2-因客户不是好友导致发送失败 3-因客户已经收到其他群发消息导致发送失败
            if (item.getStatus() == 1) {
                sendCount++;
                // 已发送
                entity.setSendStatus(PlanSendStatusEnum.SENDED.getCode());
            } else {
                failCount++;
                // 发送失败
                entity.setSendStatus(PlanSendStatusEnum.FAIL.getCode());
            }
            entity.setLogId(UniqueIdUtils.uniqueLong());
            entity.setPlanId(ownerLog.getPlanId());
            entity.setOwnLogId(ownerLog.getOwnerLogId());
            entity.setWxEnterpriseId(wxEnterpriseId);
            entity.setEnterpriseId(enterpriseId);
            entity.setStaffId(staffId);
            entity.setSendTime(sendTime);
            addList.add(entity);
        }
        // 查询群主的所有群
        GroupChatSearchQDTO chatQDTO = new GroupChatSearchQDTO() ;
        chatQDTO.setWxEnterpriseId(wxEnterpriseId);
        chatQDTO.setEnterpriseId(enterpriseId);
        chatQDTO.setStaffId(staffId);
        chatQDTO.setStatus(0);
        chatQDTO.setGicFlag(1);
        chatQDTO.setGiveUpStartTime(sendTime);
        List<GroupChatDTO> groupChatDTOList = this.groupChatMapper.list(chatQDTO);
        if(CollectionUtils.isNotEmpty(groupChatDTOList)) {
            for(GroupChatDTO chatDTO : groupChatDTOList) {
                Long groupChatId = chatDTO.getGroupChatId();
                if(!doneGroupChatIdList.contains(groupChatId)) {
                    logger.info("放弃执行的群={}",groupChatId);
                    TabGroupChatPlanLog entity = new TabGroupChatPlanLog();
                    entity.setSendStatus(PlanSendStatusEnum.GIVE_UP.getCode());
                    entity.setGroupChatId(groupChatId);
                    entity.setLogId(UniqueIdUtils.uniqueLong());
                    entity.setPlanId(ownerLog.getPlanId());
                    entity.setOwnLogId(ownerLog.getOwnerLogId());
                    entity.setWxEnterpriseId(wxEnterpriseId);
                    entity.setEnterpriseId(enterpriseId);
                    entity.setStaffId(staffId);
                    entity.setSendTime(new Date());
                    failCount = failCount+1 ;
                    addList.add(entity) ;
                }
            }
        }

        if (CollectionUtils.isNotEmpty(addList)) {
            this.groupChatPlanLogMapper.batchInsert(addList);
        }

        // 更新统计数量、状态
        if (!endFlag) {
            this.groupChatPlanOwnerLogService.updateSendCount(ownerLog.getOwnerLogId(), sendCount,
                    list.get(0).getSendTime(), failCount);
            // 完成代办
            this.pendingTaskService.updateFinish(ownerLog.getOwnerLogId() + "");
            // 更新计划统计
            this.groupChatPlanMapper.updateData(ownerLog.getPlanId(), 1, sendCount, failCount);
        }
    }

    @Override
    public void del(String clerkId, String clerkName, Long planId) {
        this.addOrDelTimer(planId, new Date(), 0);
        this.groupChatPlanMapper.deleteById(planId, clerkId, clerkName);
    }

    @Override
    public void stop(String clerkId, String clerkName, Long planId) {
        logger.info("终止计划,并触发统计planId={}", planId);
        Integer modifyStartTimeFlag = null;
        TabGroupChatPlan plan = this.groupChatPlanMapper.selectById(planId);
        if (plan.getStartTime().getTime() >= new Date().getTime()) {
            modifyStartTimeFlag = 1;
        }
        this.groupChatPlanMapper.stopById(planId, clerkId, clerkName, modifyStartTimeFlag);
        // 停止企微发送
        if(plan.getExecType()==0) {
            CommonMQDTO dto = new CommonMQDTO();
            dto.setType(4);
            Map<String,String> map = new HashMap<>() ;
            map.put("planId", planId+"") ;
            dto.setParams(map);
            this.haobanCommonMQApiService.putCommonMessage(dto);
        }
        this.putMQForData(planId);
    }

    @Override
    public Page<GroupChatPlanLogDTO> listLogPage(GroupChatPlanSearchQDTO qdto, BasePageInfo basePageInfo) {
        PageHelper.startPage(basePageInfo);
        if (StringUtils.isNotBlank(qdto.getSearchParams())) {
            String params = qdto.getSearchParams();
            qdto.setSearchParams("%" + params + "%");
        }
        if (StringUtils.isNotBlank(qdto.getChatName())) {
            String params = qdto.getChatName();
            qdto.setChatName("%" + params + "%");
            qdto.setWxChatId(params + "%");
        }
        List<GroupChatPlanLogDTO> list = this.groupChatPlanLogMapper.listPlanLog(qdto);
        if (CollectionUtils.isNotEmpty(list)) {
            Set<String> clerkIdList = list.stream().filter(dto -> StringUtils.isNotBlank(dto.getClerkId()))
                    .map(dto -> dto.getClerkId()).collect(Collectors.toSet());
            if (CollectionUtils.isNotEmpty(clerkIdList)) {
                List<ClerkDTO> clerkList = this.clerkService.getClerkByClerkIds(clerkIdList);
                if (CollectionUtils.isNotEmpty(clerkList)) {
                    Map<String, ClerkDTO> map = clerkList.stream()
                            .collect(Collectors.toMap(ClerkDTO::getClerkId, dto -> dto, (k1, k2) -> k1));
                    list.forEach(dto -> {
                        String clerkId = dto.getClerkId();
                        if (StringUtils.isNotBlank(clerkId) && null != map.get(clerkId)) {
                            dto.setClerkCode(map.get(clerkId).getClerkCode());
                            dto.setClerkName(map.get(clerkId).getClerkName());
                        }
                    });
                }
            }
            List<String> storeIdList = list.stream().filter(dto -> StringUtils.isNotBlank(dto.getStoreId()))
                    .map(dto -> dto.getStoreId()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(storeIdList)) {
                String[] arr = new String[storeIdList.size()];
                for (int i = 0; i < storeIdList.size(); i++) {
                    arr[i] = storeIdList.get(i);
                }
                List<StoreDTO> storeList = this.storeService.getStores(arr);
                Map<String, StoreDTO> map = storeList.stream()
                        .collect(Collectors.toMap(StoreDTO::getStoreId, dto -> dto, (k1, k2) -> k1));
                list.forEach(dto -> {
                    String storeId = dto.getStoreId();
                    if (StringUtils.isNotBlank(storeId) && null != map.get(storeId)) {
                        dto.setStoreCode(map.get(storeId).getStoreCode());
                        dto.setStoreName(map.get(storeId).getStoreName());
                    }
                });
            }
        }
        Page<GroupChatPlanLogDTO> retPage = PageHelperUtils.changePageHelperToCurrentPage(list,
                GroupChatPlanLogDTO.class);
        return retPage;
    }

    @Override
    public void staffSendResult(StaffSendResultQDTO qdto ) {
        String wxEnterpriseId = qdto.getWxEnterpriseId() ;
        String staffId = qdto.getStaffId() ;
        Long planId = qdto.getPlanId() ;
        String failRemark = qdto.getFailRemark() ;
        Date sendTime = qdto.getSendTime() ;
        if(StringUtils.isNotBlank(failRemark)) {
            this.groupChatPlanOwnerLogMapper.staffSendResult(staffId,planId,sendTime,failRemark,3) ;
            logger.info("好办小程序发送失败={}",failRemark);
            return;
        }else {
            this.groupChatPlanOwnerLogMapper.staffSendResult(staffId,planId,sendTime,failRemark,2) ;
        }
        GroupChatPlanOwnerLogDTO  dto  = this.groupChatPlanOwnerLogService.getOwnerInfo(planId,staffId,null,wxEnterpriseId) ;
        this.updateMsgid(dto);
    }

    public void addOrDelTimer(Long planId, Date sendTime, int status) {
        logger.info("添加1/删除0定时,{},{}", status, planId);
        QuartzTaskDTO quartzTask = new QuartzTaskDTO();
        quartzTask.setTaskStatus(status);
        String taskTimeInfo = this.getTaskTime(sendTime);
        quartzTask.setTaskTimeInfo(taskTimeInfo);
        quartzTask.setTaskService("com.gic.haoban.manage.api.service.chat.GroupChatPlanApiService");
        quartzTask.setTaskMethod("doPlanTimer");
        quartzTask.setTaskParam(planId + "");
        quartzTask.setReferId(planId + "");
        try {
            quartzService.addOrUpdateQuartzTask(quartzTask);
        } catch (Exception e) {
            logger.warn("提交定时任务异常", e);
        }
    }

    private String getTaskTime(Date date) {
        String timeInfo = DateUtil.dateToStr(date, "yyyyMMddHHmmss");
        String year = timeInfo.substring(0, 4);
        int month = Integer.parseInt(timeInfo.substring(4, 6));
        int day = Integer.parseInt(timeInfo.substring(6, 8));
        int hour = Integer.parseInt(timeInfo.substring(8, 10));
        int minute = Integer.parseInt(timeInfo.substring(10, 12));
        int second = Integer.parseInt(timeInfo.substring(12, 14));
        String time = new StringBuilder().append(second).append(" ").append(minute).append(" ").append(hour).append(" ")
                .append(day).append(" ").append(month).append(" ").append(year).toString();
        return time;
    }

    @Override
    public void updateRemark(GroupChatPlanDTO dto) {
        this.groupChatPlanMapper.updateRemark(dto);
    }


    @Override
    public void cancelSendTimer(String params) {
        logger.info("过期取消发送={}",params);
        List<GroupChatPlanOwnerLogDTO>  list =   this.groupChatPlanOwnerLogMapper.listForCancelSend();
        if(CollectionUtils.isNotEmpty(list)) {
            for(GroupChatPlanOwnerLogDTO dto : list) {
                this.cancelSend(dto);
            }
        }
    }

    @Override
    public void stopByMsgid(Long planId) {
        logger.info("终止群群发送={}",planId);
        List<Long> list = this.groupChatPlanOwnerLogMapper.listForTimer(planId);
        if(CollectionUtils.isNotEmpty(list)) {
            for(Long ownerLogId : list) {
                TabGroupChatPlanOwnerLog tab = this.groupChatPlanOwnerLogService.getById(ownerLogId) ;
                if(null != tab) {
                    GroupChatPlanOwnerLogDTO dto = EntityUtil.changeEntityByJSON(GroupChatPlanOwnerLogDTO.class, tab);
                    this.cancelSend(dto);
                }
            }
        }
    }

    private void cancelSend(GroupChatPlanOwnerLogDTO dto) {
        try {
            String wxEnterpriseId = dto.getWxEnterpriseId();
            String msgid = dto.getMsgid();
            WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId);
            if(null == qwDTO) {
                return;
            }
            String secret = config.getWxSuiteid();
            if (qwDTO.isSelf()) {
                secret = qwDTO.getSelfSecret();
            }
            ServiceResponse<Void> resp = this.qywxSuiteApiService.cancelGroupmsgSend(qwDTO.getThirdCorpid(), secret, msgid, qwDTO.isSelf(), qwDTO.getUrlHost());
            if (resp.isSuccess()) {
                this.groupChatPlanOwnerLogMapper.giveUp(dto.getOwnerLogId());
            }
        }catch (Exception e) {
            logger.info("异常",e);
        }
    }

    @Override
    public void groupChatMsgidTimer(String params) {
        logger.info("社群群发获取msgid");
        List<GroupChatPlanOwnerLogDTO>  list = this.groupChatPlanOwnerLogMapper.listForMsgid();
        if(CollectionUtils.isNotEmpty(list)) {
            for(GroupChatPlanOwnerLogDTO dto : list) {
                this.updateMsgid(dto);
            }
        }
    }

    private void updateMsgid(GroupChatPlanOwnerLogDTO dto) {
        try{
            if(null == dto) {
                return;
            }
            Long ownerLogId = dto.getOwnerLogId() ;
            String staffId = dto.getStaffId() ;
            Date sendTime = dto.getSendTime() ;
            String msgid = this.getQwMsgId(staffId,sendTime,GroupMessageServiceImpl.GroupMsgChatType.group) ;
            if(null != msgid) {
                logger.info("获取msgid={},{}",ownerLogId,msgid);
                this.groupChatPlanOwnerLogMapper.updateMsgid(ownerLogId,msgid);
                CommonMQDTO mq = new CommonMQDTO() ;
                mq.setType(5) ;
                Map<String,String> map = new HashMap<>() ;
                map.put("ownerLogId",ownerLogId+"") ;
                mq.setParams(map);
                this.haobanCommonMQApiService.putCommonDelayMessage(mq, 60);
            }
        }catch (Exception e) {
            logger.info("异常",e);
        }
    }

    @Override
    public String getQwMsgId(String staffId , Date sendTime, GroupMessageServiceImpl.GroupMsgChatType groupMsgChatType) {
        Date startTime =  DateUtil.addNumForSecond(sendTime,-30) ;
        Date endTime = DateUtil.addNumForMinute(sendTime,1) ;
        TabHaobanStaff staff =  this.staffMapper.selectByPrimaryKey(staffId) ;
        String wxEnterpriseId = staff.getWxEnterpriseId() ;
        WxEnterpriseQwDTO qwDTO = this.wxEnterpriseService.getQwInfo(wxEnterpriseId) ;
        String wxUserId = staff.getWxUserId() ;
        if(qwDTO.needOpenUserId3th()) {
            wxUserId = staff.getWxOpenUseId() ;
        }
        // 发送到群
        List<QywxGroupMessageInfoDTO> msgList = this.queryGroupMsg(groupMsgChatType,startTime, endTime, qwDTO, wxUserId);
        if(CollectionUtils.isNotEmpty(msgList)) {
            if(msgList.size()==0) {
                return msgList.get(0).getMsgId() ;
            }else {
                return msgList.get(msgList.size()-1).getMsgId() ;
            }
        }
        return null ;
    }

    private List<QywxGroupMessageInfoDTO> queryGroupMsg(GroupMessageServiceImpl.GroupMsgChatType groupMsgChatType, Date startTime, Date endTime , WxEnterpriseQwDTO qwDTO , String qwUserId) {
        QywxGroupMessageQDTO qdto = new QywxGroupMessageQDTO();
        qdto.setCorpid(qwDTO.getThirdCorpid());
        qdto.setCreator(qwUserId);
        qdto.setStartTime(startTime.getTime() / 1000);
        qdto.setEndTime(endTime.getTime() / 1000);
        qdto.setSuiteid(qwDTO.getSelf3thSecret());
        qdto.setChatType(groupMsgChatType.getCode());
        qdto.setPageSize(100);
        ServiceResponse<QywxGroupMsgResp> resp = this.qywxSuiteApiService.queryQywxGroupMessageList(qdto,qwDTO.isSelf(),qwDTO.getUrlHost());
        logger.info("查询msgid,企微返回={},{}",JSONObject.toJSONString(qdto),JSONObject.toJSONString(resp));
        if (!resp.isSuccess() || CollectionUtils.isEmpty(resp.getResult().getGroupMessageInfos())) {
            return Collections.emptyList();
        }
        return resp.getResult().getGroupMessageInfos();
    }

    @Override
    public void noticeTimer(String params) {
        // 生成数据
        //获取所有的企业
        List<String> enterpriseIdList = this.wxEnterpriseRelatedMapper.findAllEnterpriseId();
        if (CollectionUtils.isEmpty(enterpriseIdList)) {
            logger.info("任务自动刷新定时器触发, 企业id列表为空");
            return;
        }
        for (String enterpriseId : enterpriseIdList) {
            TaskSettingDTO dto = this.settingApiService.findByEnterpriseIdAndType(enterpriseId,1) ;
            if(null != dto.getNoticeFlag() && dto.getNoticeFlag()==1) {
                this.massTaskData(enterpriseId);
            }
        }
    }

    private void massTaskData(String enterpriseId) {
        logger.info("生成社群数据={}",enterpriseId);
        Date date = DateUtil.getEndTimeOfDay() ;
        List<String> clerkIdList = this.staffClerkRelationService.listAllClerkIdsByEnterpriseId(enterpriseId) ;
        if(CollectionUtils.isNotEmpty(clerkIdList)) {
            for(String clerkId : clerkIdList) {
                int total = this.groupChatPlanOwnerLogMapper.getTotalTask(enterpriseId,clerkId,date) ;
                logger.info("clerkId={}",total);
                if(total > 0) {
                    int invalid = this.groupChatPlanOwnerLogMapper.getInvalidTask(enterpriseId,clerkId,date) ;
                    this.qywxGroupSendCanvasApiService.saveNoticeLog(enterpriseId,clerkId,total,0,invalid,"chat") ;
                }
                // 朋友圈
                int momentTotal = this.qwMomentPlanAttendMapper.getTotalTask(enterpriseId,clerkId,date) ;
                if(momentTotal > 0) {
                    int invalid = this.qwMomentPlanAttendMapper.getInvalidTask(enterpriseId,clerkId,date) ;
                    this.qywxGroupSendCanvasApiService.saveNoticeLog(enterpriseId,clerkId,momentTotal,0,invalid,"moment") ;
                }
            }
        }
    }

    @Override
    public Integer getTaskNum(String wxEnterpriseId, String enterpriseId, String storeId, String clerkId, String staffId) {
        ClerkDTO clerkDTO = this.clerkService.getclerkById(clerkId) ;
        if(null == clerkDTO) {
            return 0 ;
        }
        if(clerkDTO.getClerkType()==1) {
            clerkId = null ;
        }
        int total = this.groupChatPlanOwnerLogMapper.getTaskNum(enterpriseId,clerkId,storeId,staffId) ;
        return total;
    }
}