package com.fs.sop.service.impl;


import com.alibaba.fastjson.JSON;
import com.fs.common.core.domain.R;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.utils.StringUtils;
import com.fs.course.domain.FsCourseWatchLog;
import com.fs.course.service.IFsCourseWatchLogService;
import com.fs.fastGpt.service.IFastGptChatSessionService;
import com.fs.qw.domain.QwExternalContact;
import com.fs.qw.domain.QwUser;
import com.fs.qw.mapper.QwExternalContactMapper;
import com.fs.qw.mapper.QwUserMapper;
import com.fs.qw.param.SopMsgParam;
import com.fs.qw.result.QwExternalContactByQwResult;
import com.fs.qw.service.impl.AsyncSopTestService;
import com.fs.qw.service.impl.QwExternalContactServiceImpl;
import com.fs.qw.vo.QwSopTempSetting;
import com.fs.qwApi.Result.QwAddMsgTemplateResult;
import com.fs.qwApi.Result.QwGroupmsgSendResult;
import com.fs.qwApi.Result.QwUploadImgResult;
import com.fs.qwApi.Result.SendItemResult;
import com.fs.qwApi.param.QwExternalContactHParam;
import com.fs.qwApi.param.QwGetGroupmsgSendParam;
import com.fs.qwApi.param.QwMsgTemplateSop;
import com.fs.qwApi.service.QwApiService;
import com.fs.sop.domain.QwSopLogs;
import com.fs.sop.mapper.QwSopLogsMapper;
import com.fs.sop.mapper.SopUserLogsInfoMapper;
import com.fs.sop.params.GetQwSopLogsByJsApiParam;
import com.fs.sop.params.QwSopLogsParam;
import com.fs.sop.params.SendSopParamDetailsC;
import com.fs.sop.service.IQwSopLogsService;
import com.fs.sop.vo.QwSopLogsDoSendListTVO;
import com.fs.sop.vo.QwSopLogsListCVO;
import com.fs.voice.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 企业微信SOP  定时任务Service业务层处理
 *
 * @author fs
 * @date 2024-08-05
 */
@Service
public class QwSopLogsServiceImpl implements IQwSopLogsService
{

    private static final Logger logger = LoggerFactory.getLogger(QwSopLogsServiceImpl.class);
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private QwSopLogsMapper qwSopLogsMapper;

    @Autowired
    private QwApiService qwApiService;

    @Autowired
    private IQwSopLogsService qwSopLogsService;

    @Autowired
    private QwExternalContactServiceImpl qwExternalContactService;

    @Autowired
    private IFsCourseWatchLogService watchLogService;

    @Autowired
    private QwUserMapper qwUserMapper;

    @Autowired
    private QwExternalContactMapper qwExternalContactMapper;

    @Autowired
    private SopUserLogsInfoMapper sopUserLogsInfoMapper;

    @Autowired
    private AsyncSopTestService asyncSopTestService;


    @Lazy
    @Autowired
    private IFastGptChatSessionService fastGptChatSessionService;


    /**
     * 查询企业微信SOP  定时任务
     *
     * @param id 企业微信SOP  定时任务主键
     * @return 企业微信SOP  定时任务
     */
    @Override
    public QwSopLogs selectQwSopLogsById(String id)
    {
        return qwSopLogsMapper.selectQwSopLogsById(id);
    }

    /**
     * 查询企业微信SOP  定时任务列表
     *
     * @param QwSopLogs 企业微信SOP  定时任务
     * @return 企业微信SOP  定时任务
     */
    @Override
    public List<QwSopLogs> selectQwSopLogsList(QwSopLogs QwSopLogs)
    {
        return qwSopLogsMapper.selectQwSopLogsList(QwSopLogs);
    }

    /**
     * 获取单条规则 的 执行记录历史
     */
    @Override
    public List<QwSopLogsListCVO> selectQwSopLogsListBySopId(QwSopLogsParam param) {

        switch (param.getType()){
            //个微
            case 1:
                return qwSopLogsMapper.selectQwSopLogsListByGwSopId(param);
            //企微
            case 2:
                return qwSopLogsMapper.selectQwSopLogsListByQwSopId(param);
        }
       return null;
    }


    /**
     * 新增企业微信SOP  定时任务
     *
     * @param QwSopLogs 企业微信SOP  定时任务
     * @return 结果
     */
    @Override
    public int insertQwSopLogs(QwSopLogs QwSopLogs)
    {
        return  qwSopLogsMapper.insertQwSopLogs(QwSopLogs);
    }

    /**
     * 修改企业微信SOP  定时任务
     *
     * @param QwSopLogs 企业微信SOP  定时任务
     * @return 结果
     */
    @Override
    public int updateQwSopLogs(QwSopLogs QwSopLogs)
    {
        return qwSopLogsMapper.updateQwSopLogs(QwSopLogs);
    }

    @Override
    public int editCourseQwSopLogs(String[] ids) {
        return qwSopLogsMapper.editCourseQwSopLogs(ids);
    }

    /**
     * 批量删除企业微信SOP  定时任务
     *
     * @param ids 需要删除的企业微信SOP  定时任务主键
     * @return 结果
     */
    @Override
    public int deleteQwSopLogsByIds(String[] ids)
    {
        return qwSopLogsMapper.deleteQwSopLogsByIds(ids);
    }

    /**
     * 删除企业微信SOP  定时任务信息
     *
     * @param id 企业微信SOP  定时任务主键
     * @return 结果
     */
    @Override
    public int deleteQwSopLogsById(String id)
    {
        return qwSopLogsMapper.deleteQwSopLogsById(id);
    }

    /**
     *  检索执行符合条件的定时任务
     */
    @Override
    public void checkQwSopLogs() {

        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.checkQwSopLogs();

        //发送消息组件表
        QwMsgTemplateSop templateSop= new QwMsgTemplateSop();

        templateSop.setChatType("single");
        templateSop.setAllowSelect(false);
        List<QwMsgTemplateSop.Attachment> attachmentLists=new ArrayList<>();

        // 创建一个 Map，用于分组：key 是 qwUserid + sendTime + sopId，value 是对应的 QwSopLogs 列表
        Map<String, List<QwSopLogs>> groupedLogs = qwSopLogs.stream()
                .collect(Collectors.groupingBy(log -> log.getQwUserid() + "|"
                        + log.getSendTime() + "|"
                        + log.getSopId()+"|"+log.getCorpId()));

        // 遍历分组数据
        for (Map.Entry<String, List<QwSopLogs>> entry : groupedLogs.entrySet()) {
            String key = entry.getKey();
            // 分组的 key（qwUserid|sendTime|sopId）
            List<QwSopLogs> logs = entry.getValue(); // 分组对应的日志列表

            // 从 key 中提取 qwUserid
            String qwUserid = key.split("\\|")[0];
            String corpId  = key.split("\\|")[3];



            // 收集 externalUserId 的去重集合
            Set<String> externalUserIds = logs.stream()
                    .map(QwSopLogs::getExternalUserId)
                    .filter(Objects::nonNull) // 过滤 null 值
                    .collect(Collectors.toSet());
            List<String> externalUserIdsCollect = new ArrayList<>(externalUserIds);


            // 收集唯一的 contentJson
            Set<String> uniqueContentJsons = logs.stream()
                    .map(QwSopLogs::getContentJson)
                    .filter(Objects::nonNull) // 过滤 null 值
                    .collect(Collectors.toSet());

            List<String> uniqueContentJsonList = new ArrayList<>(uniqueContentJsons);

            // 获取 QwSopLogs 的 id 列表
            List<String> ids = logs.stream()
                    .map(QwSopLogs::getId)
                    .collect(Collectors.toList());
            List<String> collectIds= new ArrayList<>(ids);



            QwSopTempSetting.Content content = JSON.parseObject(uniqueContentJsonList.get(0), QwSopTempSetting.Content.class);

            List<QwSopTempSetting.Content.Setting> setting = content.getSetting();
            setting.forEach(set -> {
                String contentType = set.getContentType();
                switch (contentType){
                    //文本
                    case "1":
                        templateSop.setTextContent(set.getValue());
                        break;
                    //图片
                    case "2":
                        if(!StringUtil.strIsNullOrEmpty(set.getImgUrl())){

                            QwUploadImgResult uploadimg = null;
                            try {

                                uploadimg = qwApiService.uploadimgs(set.getImgUrl(), corpId);

                                if (uploadimg.getErrcode()!=0){
                                    logger.error("SOP企业微信接口图片上传失败:{}", uploadimg.getErrMsg());
                                }else {
                                    QwMsgTemplateSop.Attachment attachment=new QwMsgTemplateSop.Attachment();
                                    attachment.setType(2);
                                    attachment.setImagePicUrl(uploadimg.getUrl());
                                    attachmentLists.add(attachment);
                                }



                            } catch (Exception e) {
                                logger.error("SOP企业微信接口图片上传失败",e);
                            }

                        }

                        break;
                    //链接
                    case "3":
                        if(!StringUtil.strIsNullOrEmpty(set.getLinkImageUrl())){
                            try {
                                QwMsgTemplateSop.Attachment attachment=new QwMsgTemplateSop.Attachment();
                                attachment.setType(3);
                                attachment.setLinkTitle(set.getLinkTitle());
                                attachment.setLinkPicurl(set.getLinkImageUrl());
                                attachment.setLinkDesc(set.getLinkDescribe());
                                attachment.setLinkUrl(set.getLinkUrl());
                                attachmentLists.add(attachment);

                            } catch (Exception e) {
                                logger.error("SOP企业微信接口链接图片上传失败",e);
                            }

                        }

                        break;
                }

            });

            templateSop.setSender(qwUserid);
            templateSop.setAttachments(attachmentLists);

            // 设置批次大小，假设每批最多处理10000个用户
            int batchSize = 10000;
            int totalSize = externalUserIdsCollect.size();
            int startIndex = 0;

            // 按批次处理
            while (startIndex < totalSize) {
                // 获取当前批次的用户列表
                int endIndex = Math.min(startIndex + batchSize, totalSize);
                List<String> currentBatch = externalUserIdsCollect.subList(startIndex, endIndex);

                // 创建新的 templateSop 对象，并设置当前批次的 externalUseridList
                templateSop.setExternalUseridList(currentBatch);

                // 调用 API 发送消息模板
                QwAddMsgTemplateResult qwAddMsgTemplateResult = qwApiService.addMsgTemplateBySop(templateSop, corpId);

                // 批量更新
                if (qwAddMsgTemplateResult.getErrCode() == 0 || qwAddMsgTemplateResult.getErrCode() == 41063) {
                    qwSopLogsMapper.updateQwSopLogsBycollectIds(collectIds, 1L, qwAddMsgTemplateResult.getMsgId());
                } else {
                    qwSopLogsMapper.updateQwSopLogsBycollectIds(collectIds, 0L, qwAddMsgTemplateResult.getMsgId());
                }

                // 更新 startIndex 继续处理下一批次
                startIndex = endIndex;
            }

//            templateSop.setSender(qwUserid);
//            templateSop.setExternalUseridList(externalUserIdsCollect);
//            templateSop.setAttachments(attachmentLists);
//
//            QwAddMsgTemplateResult qwAddMsgTemplateResult = qwApiService.addMsgTemplateBySop(templateSop, corpId);
//
//            //批量更新
//            if (qwAddMsgTemplateResult.getErrCode() == 0 || qwAddMsgTemplateResult.getErrCode()==41063) {
//                qwSopLogsMapper.updateQwSopLogsBycollectIds(collectIds,1L,qwAddMsgTemplateResult.getMsgId());
//            }else {
//                qwSopLogsMapper.updateQwSopLogsBycollectIds(collectIds,0L,qwAddMsgTemplateResult.getMsgId());
//            }

        }

    }

    /**
     *  检查企微官方群发的发送结果
     *  未成功的更新为群发助手发送
     */
    @Override
    public void qwSopLogsResult() {
        logger.info("开始执行企业微信群发消息结果查询任务");
        long startTime = System.currentTimeMillis();

        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.selectSopLogsByCreateCorpMassSendResult();
        if (qwSopLogs.isEmpty()) {
            logger.info("没有需要查询结果的群发消息记录");
            return;
        }

        logger.info("需要处理的群发消息记录数量: {}", qwSopLogs.size());

        // 按企业ID分组处理，避免并发请求超过企业微信接口限制
        Map<String, List<QwSopLogs>> corpGroupedLogs = qwSopLogs.stream()
                .collect(Collectors.groupingBy(QwSopLogs::getCorpId));

        logger.info("按企业ID分组后，共有{}个企业需要处理", corpGroupedLogs.size());

        // 创建线程池，只对企业进行多线程处理
        int threadCount = Math.min(10, Runtime.getRuntime().availableProcessors());
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        CountDownLatch mainLatch = new CountDownLatch(corpGroupedLogs.size());

        // 对每个企业创建一个任务
        for (Map.Entry<String, List<QwSopLogs>> entry : corpGroupedLogs.entrySet()) {
            String corpId = entry.getKey();
            List<QwSopLogs> corpLogs = entry.getValue();

            executorService.submit(() -> {
                try {
                    logger.info("开始处理企业ID: {}，记录数量: {}", corpId, corpLogs.size());
                    List<QwSopLogs> updateList = new ArrayList<>();

                    // 同步处理每条记录
                    for (QwSopLogs sopLog : corpLogs) {
                        try {
                            // 添加随机延迟，避免请求过于集中
                            Thread.sleep(100 + new Random().nextInt(100));

                            QwGetGroupmsgSendParam qwGetGroupmsgSendParam = new QwGetGroupmsgSendParam();
                            qwGetGroupmsgSendParam.setMsgid(sopLog.getMsgId());
                            qwGetGroupmsgSendParam.setUserid(sopLog.getQwUserid());

                            QwGroupmsgSendResult groupmsgSendResult = qwApiService.getGroupmsgSendResult(qwGetGroupmsgSendParam, sopLog.getCorpId());

                            if (groupmsgSendResult.getErrCode() == 0) {
                                List<SendItemResult> sendList = groupmsgSendResult.getSendList();
                                for (SendItemResult itemResult : sendList) {
                                    QwSopLogs logCopy = new QwSopLogs();
                                    logCopy.setId(sopLog.getId());

                                    if (itemResult.getStatus() != 1 && itemResult.getStatus() != 0) {
                                        logCopy.setSendType(2);
                                        logCopy.setSendStatus(3L);
                                        logCopy.setRemark("补发");
                                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                                        LocalDateTime currentTime = LocalDateTime.now();
                                        String newTimeString = currentTime.format(formatter);
                                        logCopy.setSendTime(newTimeString);
                                        logCopy.setSort(3);
                                    } else {

                                        logCopy.setReceivingStatus(Long.valueOf(itemResult.getStatus()));

                                        if (itemResult.getStatus() == 0) {
                                            logCopy.setSendStatus(5L);
                                            logCopy.setRemark("员工未发送,已作废");
                                        }

                                    }
                                    updateList.add(logCopy);
                                }
                            } else if (groupmsgSendResult.getErrCode() == 45033 || groupmsgSendResult.getErrCode() == 40001) {
                                // 接口调用频率超过限制或不合法的access_token
                                logger.warn("企业微信接口调用频率超限，企业ID: {}，错误码: {}，错误信息: {}，MsgId: {}",
                                        sopLog.getCorpId(), groupmsgSendResult.getErrCode(),
                                        groupmsgSendResult.getErrMsg(), sopLog.getMsgId());
                                // 增加更长的延迟后重试
                                Thread.sleep(2000 + new Random().nextInt(1000));

                                // 重新尝试请求
                                groupmsgSendResult = qwApiService.getGroupmsgSendResult(qwGetGroupmsgSendParam, sopLog.getCorpId());

                                if (groupmsgSendResult.getErrCode() == 0) {
                                    List<SendItemResult> sendList = groupmsgSendResult.getSendList();
                                    for (SendItemResult itemResult : sendList) {
                                        QwSopLogs logCopy = new QwSopLogs();
                                        logCopy.setId(sopLog.getId());

                                        if (itemResult.getStatus() != 1  && itemResult.getStatus() != 0 ) {
                                            logCopy.setSendType(2);
                                            logCopy.setSendStatus(3L);
                                            logCopy.setSort(3);
                                            logCopy.setRemark("补发");
                                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                                            LocalDateTime currentTime = LocalDateTime.now();
                                            String newTimeString = currentTime.format(formatter);
                                            logCopy.setSendTime(newTimeString);
                                        }else {
                                            logCopy.setReceivingStatus(Long.valueOf(itemResult.getStatus()));
                                            if (itemResult.getStatus() == 0) {
                                                logCopy.setSendStatus(5L);
                                                logCopy.setRemark("员工未发送,已作废");
                                            }
                                        }
                                        updateList.add(logCopy);
                                    }
                                } else {
                                    logger.error("重试后仍获取群发消息结果失败，企业ID: {}，错误码: {}，错误信息: {}，MsgId: {}",
                                            sopLog.getCorpId(), groupmsgSendResult.getErrCode(),
                                            groupmsgSendResult.getErrMsg(), sopLog.getMsgId());
                                }
                            } else {
                                logger.warn("获取群发消息结果失败，企业ID: {}，错误码: {}，错误信息: {}，MsgId: {}",
                                        sopLog.getCorpId(), groupmsgSendResult.getErrCode(),
                                        groupmsgSendResult.getErrMsg(), sopLog.getMsgId());
                            }

                            // 每处理50条记录，批量更新一次数据库
                            if (updateList.size() >= 50) {
                                batchUpdateDatabase(updateList);
                                updateList.clear();
                            }
                        } catch (Exception e) {
                            logger.error("处理群发消息结果异常，企业ID: {}，MsgId: {}", sopLog.getCorpId(), sopLog.getMsgId(), e);
                        }
                    }

                    // 处理剩余的更新
                    if (!updateList.isEmpty()) {
                        batchUpdateDatabase(updateList);
                    }

                    logger.info("企业ID: {} 处理完成", corpId);
                } catch (Exception e) {
                    logger.error("处理企业群发消息结果异常，企业ID: {}", corpId, e);
                } finally {
                    mainLatch.countDown();
                }
            });
        }

        try {
            // 等待所有企业处理完成
            boolean completed = mainLatch.await(30, TimeUnit.MINUTES);
            if (!completed) {
                logger.warn("群发消息结果查询任务未在规定时间内完成");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            logger.error("等待群发消息结果查询任务完成时被中断", e);
        } finally {
            executorService.shutdown();
        }

        long endTime = System.currentTimeMillis();
        logger.info("企业微信群发消息结果查询任务完成，处理记录总数: {}，总耗时: {}ms",
                qwSopLogs.size(), (endTime - startTime));
    }

    /**
     * 批量更新数据库
     * @param updateList 需要更新的记录列表
     */
    private void batchUpdateDatabase(List<QwSopLogs> updateList) {
        int updateBatchSize = 1000;
        for (int i = 0; i < updateList.size(); i += updateBatchSize) {
            int endIndex = Math.min(i + updateBatchSize, updateList.size());
            List<QwSopLogs> batch = updateList.subList(i, endIndex);
            try {
                qwSopLogsMapper.batchUpdateStatusByQwResult(batch);
                logger.info("批量修改 sopLogs 成功，修改数量: " + batch.size());
            } catch (Exception e) {
                logger.error("批量修改 sopLogs 失败", e);
            }
        }
    }


    @Override
    public int updateQwSopLogsByWatchLogType(String id,String remark) {
        return qwSopLogsMapper.updateQwSopLogsByWatchLogType(id,remark);
    }

    @Override
    public List<QwSopLogsDoSendListTVO> selectQwSopLogsDoSendList(String qwUserId,String corpId) {
        return qwSopLogsMapper.selectQwSopLogsDoSendList(qwUserId,corpId);
    }

    @Override
    public int updateQwSopLogsBySendStatus() {
        return qwSopLogsMapper.updateQwSopLogsBySendStatus();
    }

    @Override
    public int updateQwSopLogsSendType(QwSopLogs qwSopLogs) {
       return qwSopLogsMapper.updateQwSopLogs(qwSopLogs);
    }

    @Override
    public List<QwSopLogs> selectQwSopLogsListVO(SopMsgParam param) {
        return qwSopLogsMapper.selectQwSopLogsListVO(param);
    }

    @Override
    public SendSopParamDetailsC getQwSopLogsByJsApi(GetQwSopLogsByJsApiParam param) {

        //写入企业微信 在线状态 10分钟 通过订阅方式，如果10分钟没有请求此接口，调用一个LOGIN方法
        redisCache.setCacheObject("qwActive:"+param.getCorpId()+":"+param.getQwUserId(),1,10 ,TimeUnit.MINUTES);

        logger.info("主动获取发送信息:"+param);

        // 封装消息体
        SendSopParamDetailsC sopParamDetailsC = new SendSopParamDetailsC();
        // 使用线程安全的集合
        List<QwSopLogsDoSendListTVO> sendJsApiList = Collections.synchronizedList(new ArrayList<>());
        List<QwSopLogsDoSendListTVO> sendJsApiListOver = Collections.synchronizedList(new ArrayList<>());

        // 创建一个自定义的线程池，根据实际需求调整线程数
        //ExecutorService executor = Executors.newFixedThreadPool(4);
        try {

            // 查询当前客户的完课消息
            List<QwSopLogsDoSendListTVO> logsByJsApiOver = qwSopLogsMapper.getQwSopLogsByJsApiOver(param);
            for (QwSopLogsDoSendListTVO log : logsByJsApiOver) {
                try {
                    // 使用现代的日期时间 API
                    LocalDateTime sendTime = log.getSendTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    LocalDateTime expiryDateTime = sendTime.plusHours(12);
                    LocalDateTime now = LocalDateTime.now();

                    // 判断是否过期
                    if (now.isAfter(expiryDateTime)) {
                        // 作废消息
                        qwSopLogsService.updateQwSopLogsByWatchLogType(log.getId(), "已过期，不发送");
                    } else {
                        sendJsApiListOver.add(log);
                    }
                } catch (Exception e) {
                    // 记录错误日志
                    logger.error("Error processing log in logsByJsApiOver: {}", log.getId()+":"+e);
                }
            }
            // 查询当前客户的待发送记录
            List<QwSopLogsDoSendListTVO> logsByJsApi = qwSopLogsMapper.getQwSopLogsByJsApi(param);

            // 查询员工信息的id
            QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(),param.getQwUserId().trim());

            Long qwId=qwUser.getId();

            sopParamDetailsC.setAppKey(qwUser.getAppKey());

            // 客户的信息
            QwExternalContactHParam contactHParam = new QwExternalContactHParam();
            contactHParam.setUserId(param.getQwUserId().trim());
            contactHParam.setExternalUserId(param.getExternalUserId().trim());
            contactHParam.setCorpId(param.getCorpId().trim());
            Long qwExternalContactId = qwExternalContactMapper.getQwExternalContactId(contactHParam);
            for (QwSopLogsDoSendListTVO log : logsByJsApi) {

                try {
                    QwSopTempSetting.Content content = JSON.parseObject(log.getContentJson(), QwSopTempSetting.Content.class);
                    List<QwSopTempSetting.Content.Setting> setting = content.getSetting().stream().filter(e -> "9".equals(e.getContentType())).collect(Collectors.toList());

                    //有app的异步推送消息
                    if (!setting.isEmpty()) {
                        asyncSopTestService.asyncSendMsgBySopAppLinkNormal(setting, param.getExternalId());
                    }

                    if (log.getExpiryTime() == null) {
                        // 作废消息
                        qwSopLogsService.updateQwSopLogsByWatchLogType(log.getId(), "SOP任务被删除");
                    } else {
                        Integer expiryTime = log.getExpiryTime();
                        LocalDateTime sendTime = log.getSendTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        LocalDateTime expiryDateTime = sendTime.plusHours(expiryTime);
                        LocalDateTime now = LocalDateTime.now();

                        // 判断是否过期
                        if (now.isAfter(expiryDateTime)) {
                            // 作废消息
                            qwSopLogsService.updateQwSopLogsByWatchLogType(log.getId(), "已过期，不发送");
                        } else {
                            switch (content.getType()) {
                                case 1:
                                    // 普通消息，不做判断，加入发送列表
                                    sendJsApiList.add(log);
                                    break;
                                case 2:
                                    // 课程消息，进行复杂的条件判断
                                    FsCourseWatchLog watchLog = watchLogService.getWatchCourseLogVideoBySop(
                                            Long.valueOf(content.getVideoId()),
                                            String.valueOf(qwId),
                                            qwExternalContactId
                                    );

                                    Integer courseType = content.getCourseType();
                                    String logId = log.getId();

                                    if (content.getCourseType()==null){
                                        qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "模板未选消息类型，不发送");
                                    }
                                    if (watchLog != null) {

                                        //新逻辑
                                        if (isCourseTypeValid(courseType, watchLog.getLogType())) {
                                            // 加入到发送列表中
                                            sendJsApiList.add(log);
                                        } else {
                                            // 作废消息
                                            qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "看课状态未满足，不发送");
                                        }


                                    } else {
                                        // 没有观看记录，只发普通消息
                                        if (courseType == 0) {
                                            sendJsApiList.add(log);
                                        } else {
                                            qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "无观看记录，不发送");
                                        }
                                    }
                                    break;
                                case 3:
                                    // 订单消息，不做判断，加入发送列表
                                    sendJsApiList.add(log);
                                    break;
                                case 4:
                                    // Ai消息，不加入序列单独处理
                                    try {
                                        logger.info("Ai触达消息 : {}", log.getId());
                                      //  fastGptChatSessionService.sendAiTouch(log,param.getCorpId().trim());
                                    }catch (Exception e){
                                        logger.error("Ai消息 : {}", content.getType());
                                    }
                                    break;
                                default:
                                    // 未知类型，记录警告
                                    logger.error("Unknown content type logsByJsApi: {}", content.getType());
                                    break;
                            }
                        }
                    }
                } catch (Exception e) {
                    // 记录错误日志
                    logger.error("Error processing log in logsByJsApi: {}", log.getId()+" : " + e);
                }
            }
            //获取外部联系人
            QwSopLogs qwSopLogsByJsApiNext = qwSopLogsMapper.getQwSopLogsByJsApiNext(param);

            if (qwSopLogsByJsApiNext!=null && !StringUtil.strIsNullOrEmpty(qwSopLogsByJsApiNext.getExternalUserId()) ){
                //过滤非外部联系人
                try{
                    List<String> exIds=redisCache.getCacheObject("qwUserExtIds:"+param.getCorpId()+":"+param.getQwUserId());
                    if(StringUtils.isNotEmpty(exIds)&&exIds.size()>0){
                        //查询外部联系人是否存在，如果不存在，返回下一个外部联系人
                        if(!exIds.contains(qwSopLogsByJsApiNext.getExternalUserId())){
                            //更新此外部联系人所有待发记录为作废
                            param.setExternalUserId(qwSopLogsByJsApiNext.getExternalUserId());
                            qwSopLogsMapper.updateQwSopLogsByDeleted(param);
                            //获取下一个外部联系人 最大重试10次
                            for(int i=0;i<10;i++){
                                qwSopLogsByJsApiNext = qwSopLogsMapper.getQwSopLogsByJsApiNext(param);
                                if(qwSopLogsByJsApiNext!=null&&StringUtils.isNotEmpty(qwSopLogsByJsApiNext.getExternalUserId())){
                                    //判断非外部联系人
                                    if(!exIds.contains(qwSopLogsByJsApiNext.getExternalUserId())){
                                        param.setExternalUserId(qwSopLogsByJsApiNext.getExternalUserId());
                                        qwSopLogsMapper.updateQwSopLogsByDeleted(param);
                                    }
                                    else{
                                        break;
                                    }

                                }
                                else {
                                    break;
                                }
                            }
                        }
                    }
                }
                catch (Exception e){
                }
                sopParamDetailsC.setNextExternalUserId(qwSopLogsByJsApiNext.getExternalUserId().trim());
                sopParamDetailsC.setNextExternalId(qwSopLogsByJsApiNext.getExternalId());
            }

           //获取不为空的联系人

//            try {
//                 qwSopLogsByJsApiNext =  getQwSopLogsByJsApiNext(param);
//            }catch (Exception e){
//                logger.info("/n 获取下一个需要发送联系人出错:"+e.getMessage());
//
//            }

            // Step 3: 构建发送列表


            if (sendJsApiList.size() > 2) {
                List<QwSopLogsDoSendListTVO> list = new ArrayList<>(sendJsApiList.subList(0, 2));
                if (!sendJsApiListOver.isEmpty()) {
                    list.add(sendJsApiListOver.get(0));
                }
                sopParamDetailsC.setSendList(list);
            } else {
                if (!sendJsApiListOver.isEmpty()) {
                    sendJsApiList.add(sendJsApiListOver.get(0));
                }
                sopParamDetailsC.setSendList(new ArrayList<>(sendJsApiList));
            }

            //并发太多，积压了，先注释了
//            // Step 4: 批量更新推送记录状态
//            if (!sendJsApiList.isEmpty()) {
//                processAndInsertQwSopLogsByTakeRecordsList(sopParamDetailsC.getSendList());
//            }
        }catch (Exception e){
            logger.error("主动获取发送信息失败：-"+e);
        }finally {
            // 关闭线程池
            //executor.shutdown();
        }

        return sopParamDetailsC;
    }

    // 逻辑封装方法
    private boolean isCourseTypeValid(int courseType, Integer logType) {
        switch (courseType) {
            case 0:
                return true;  // courseType == 0 直接返回 true
            case 1:
                return logType==3;  // logType == "3" 时返回 true
            case 2:
                return logType==4;  // logType == "4" 时返回 true
            case 3:
                return logType==2;  // logType == "2" 时返回 true
            case 4:
                return logType==3 || logType==4;  // logType == "3" 或 "4" 时返回 true
            default:
                return false;  // 其他情况返回 false
        }
    }



//    @Override
//    public SendSopParamDetailsC getQwSopLogsByJsApi(GetQwSopLogsByJsApiParam param) {
//
//        // 封装消息体
//        SendSopParamDetailsC sopParamDetailsC = new SendSopParamDetailsC();
//
//        // 使用线程安全的集合
//        List<QwSopLogsDoSendListTVO> sendJsApiList = Collections.synchronizedList(new ArrayList<>());
//        List<QwSopLogsDoSendListTVO> sendJsApiListOver = Collections.synchronizedList(new ArrayList<>());
//
//        // 创建一个自定义的线程池，根据实际需求调整线程数
//        ExecutorService executor = Executors.newFixedThreadPool(4);
//
//        try {
//            // Step 1: 批量更新已过期的记录
//            List<QwSopLogsDoSendListTVO> logsByJsApiNotExtId = qwSopLogsMapper.getQwSopLogsByJsApiNotExtId(param);
//            if (!logsByJsApiNotExtId.isEmpty()) {
//                processAndInsertQwSopLogs(logsByJsApiNotExtId);
//            }
//
//            // Step 2: 并行处理 logsByJsApiOver 和 logsByJsApi
//            CompletableFuture<Void> futureOver = CompletableFuture.runAsync(() -> {
//                // 查询当前客户的完课消息
//                List<QwSopLogsDoSendListTVO> logsByJsApiOver = qwSopLogsMapper.getQwSopLogsByJsApiOver(param);
//                for (QwSopLogsDoSendListTVO log : logsByJsApiOver) {
//                    try {
//                        // 使用现代的日期时间 API
//                        LocalDateTime sendTime = log.getSendTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
//                        LocalDateTime expiryDateTime = sendTime.plusHours(2);
//                        LocalDateTime now = LocalDateTime.now();
//
//                        // 判断是否过期
//                        if (now.isAfter(expiryDateTime)) {
//                            // 作废消息
//                            qwSopLogsService.updateQwSopLogsByWatchLogType(log.getId(), "已过期，不发送");
//                        } else {
//                            sendJsApiListOver.add(log);
//                        }
//                    } catch (Exception e) {
//                        // 记录错误日志
//                        logger.error("Error processing log in logsByJsApiOver: {}", log.getId()+":"+e);
//                    }
//                }
//            }, executor).exceptionally(ex -> {
//                // 记录异步任务中的异常
//                logger.error("处理已经完课消息出错logsByJsApi：", ex);
//                return null;
//            });
//
//            //处理当前联系人的消息 是否符合条件
//            CompletableFuture<Void> futureApi = CompletableFuture.runAsync(() -> {
//
//                List<QwSopLogsDoSendListTVO> sendJsApiListFor = getSendJsApiListFor(param.getCorpId(),param.getExternalUserId(), param.getQwUserId());
//                sendJsApiList.addAll(sendJsApiListFor);
//
//            }, executor).exceptionally(ex -> {
//                // 记录异步任务中的异常
//                logger.error("Exception in futureApi logsByJsApi: "+ex);
//                return null;
//            });
//
//
//            //处理下一个联系人的消息 是否符合条件
//            CompletableFuture<Void> futureApiNext = CompletableFuture.runAsync(() -> {
//
//                String nextContactId = processNextContacts(param);
//                sopParamDetailsC.setNextExternalUserId(nextContactId);
//
//            }, executor).exceptionally(ex -> {
//                // 记录异步任务中的异常
//                logger.error("Exception in futureApiNext logsByJsApi: "+ex);
//                return null;
//            });
//
//            // 等待所有异步任务完成
//            CompletableFuture.allOf(futureOver, futureApi,futureApiNext).join();
//
//
//            if (sendJsApiList.size() > 3) {
//                List<QwSopLogsDoSendListTVO> list = new ArrayList<>(sendJsApiList.subList(0, 3));
//                if (!sendJsApiListOver.isEmpty()) {
//                    list.add(sendJsApiListOver.get(0));
//                }
//                sopParamDetailsC.setSendList(list);
//            } else {
//                if (!sendJsApiListOver.isEmpty()) {
//                    sendJsApiList.add(sendJsApiListOver.get(0));
//                }
//                sopParamDetailsC.setSendList(new ArrayList<>(sendJsApiList));
//            }
//
//            // Step 4: 批量更新推送记录状态
//            if (!sendJsApiList.isEmpty()) {
//                processAndInsertQwSopLogsByTakeRecordsList(sopParamDetailsC.getSendList());
//            }
//        }catch (Exception e){
//            logger.error("主动获取发送信息失败：-"+param);
//        }finally {
//            // 关闭线程池
//            executor.shutdown();
//        }
//
//        return sopParamDetailsC;
//    }

//    private String getQwSopLogsByJsApiNext(GetQwSopLogsByJsApiParam param) {
//
//        String nextExternalUserId = qwSopLogsMapper.getQwSopLogsByJsApiNext(param);
//        if (nextExternalUserId==null&& nextExternalUserId.isEmpty()){
//            return null;
//        }
//        List<QwSopLogsDoSendListTVO> nextSendList = getSendJsApiListFor(
//                param.getCorpId(),
//                nextExternalUserId,
//                param.getQwUserId()
//        );
//        if (!nextSendList.isEmpty()) {
//            // 找到一个有可发送内容的联系人，设置 nextExternalUserId
//            return nextExternalUserId;
//        }else {
//            param.setExternalUserId(nextExternalUserId);
//            return   getQwSopLogsByJsApiNext(param);
//        }
//    }
    /**
    * 获取下一个待发送的联系人
    */
//    public String processNextContacts(GetQwSopLogsByJsApiParam param) {
//
//        // 首先，获取可能的下一个外部联系人ID
//        String nextExternalUserId = qwSopLogsMapper.getQwSopLogsByJsApiNext(param);
//
//        // 开一个循环，不断往后找
//        while (StringUtils.isNotBlank(nextExternalUserId)) {
//            // 1) 获取下一个联系人可发送列表
//            List<QwSopLogsDoSendListTVO> nextSendList = getSendJsApiListFor(
//                    param.getCorpId(),
//                    nextExternalUserId,
//                    param.getQwUserId()
//            );
//
//            // 2) 判断是否有可发送内容
//            if (!nextSendList.isEmpty()) {
//                // 找到一个有可发送内容的联系人，设置 nextExternalUserId
//                return nextExternalUserId;
//            }
//
//            // 如果为空，则继续往下找“下一个”的“下一个”...
//            param.setExternalUserId(nextExternalUserId);
//            nextExternalUserId = qwSopLogsMapper.getQwSopLogsByJsApiNext(param);
//        }
//
//
//        return null;
//    }


    /**
    * 获取联系人待发送列表
    */
    public List<QwSopLogsDoSendListTVO> getSendJsApiListFor(String corpId,
                                                            String externalUserId,
                                                            String qwUserId) {

        GetQwSopLogsByJsApiParam param=new GetQwSopLogsByJsApiParam();
            param.setCorpId(corpId);
            param.setExternalUserId(externalUserId);
            param.setQwUserId(qwUserId);

        List<QwSopLogsDoSendListTVO> sendJsApiList = new ArrayList<>();

        // 查询当前客户的待发送记录
        List<QwSopLogsDoSendListTVO> logsByJsApi = qwSopLogsMapper.getQwSopLogsByJsApi(param);

        // 查询员工信息的id
        Long qwId = qwUserMapper.selectQwUserByQwUserIdAndCorpIdToId(param.getQwUserId(), param.getCorpId());

        // 客户的信息
        QwExternalContactHParam contactHParam = new QwExternalContactHParam();
        contactHParam.setUserId(param.getQwUserId());
        contactHParam.setExternalUserId(param.getExternalUserId());
        contactHParam.setCorpId(param.getCorpId());

        Long qwExternalContactId = qwExternalContactMapper.getQwExternalContactId(contactHParam);

        for (QwSopLogsDoSendListTVO log : logsByJsApi) {

            try {
                QwSopTempSetting.Content content = JSON.parseObject(log.getContentJson(), QwSopTempSetting.Content.class);

                if (log.getExpiryTime() == null) {
                    // 作废消息
                    qwSopLogsService.updateQwSopLogsByWatchLogType(log.getId(), "SOP任务被删除");
                }
                else {
                    Integer expiryTime = log.getExpiryTime();
                    LocalDateTime sendTime = log.getSendTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    LocalDateTime expiryDateTime = sendTime.plusHours(expiryTime);
                    LocalDateTime now = LocalDateTime.now();

                    // 判断是否过期
                    if (now.isAfter(expiryDateTime)) {
                        // 作废消息
                        qwSopLogsService.updateQwSopLogsByWatchLogType(log.getId(), "已过期，不发送");
                    } else {
                        switch (content.getType()) {
                            case 1:
                                // 普通消息，不做判断，加入发送列表
                                sendJsApiList.add(log);
                                break;
                            case 2:
                                // 课程消息，进行复杂的条件判断
                                FsCourseWatchLog watchLog = watchLogService.getWatchCourseLogVideoBySop(
                                        Long.valueOf(content.getVideoId()),
                                        String.valueOf(qwId),
                                        qwExternalContactId
                                );

                                Integer courseType = content.getCourseType();
                                String logId = log.getId();

                                if (watchLog != null) {

                                    //新逻辑
                                    if (isCourseTypeValid(courseType, watchLog.getLogType())) {
                                        // 加入到发送列表中
                                        sendJsApiList.add(log);
                                    } else {
                                        // 作废消息
                                        qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "看课状态未满足，不发送");
                                    }

                                } else {
                                    // 没有观看记录，只发普通消息
                                    if (courseType == 0) {
                                        sendJsApiList.add(log);
                                    } else {
                                        qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "无观看记录，不发送");
                                    }
                                }
                                break;
                            case 3:
                                // 订单消息，不做判断，加入发送列表
                                sendJsApiList.add(log);
                                break;
                            case 4:
                                // Ai消息，不加入序列单独处理
                                try {
                                    logger.info("Ai触达消息 : {}", log.getId());
                                    fastGptChatSessionService.sendAiTouch(log,param.getCorpId().trim());
                                }catch (Exception e){
                                    logger.error("Ai消息 : {}", content.getType());
                                }
                                break;
                            default:
                                // 未知类型，记录警告
                                logger.error("Unknown content type logsByJsApi: {}", content.getType());
                                break;
                        }
                    }
                }
            } catch (Exception e) {
                // 记录错误日志
                logger.error("Error processing log in logsByJsApi: {}", log.getId()+" : " + e);
            }
        }

        return sendJsApiList;
    }

    @Override
    public QwExternalContactByQwResult getExternalContactByAppKey(String appKey) {

        return  qwExternalContactMapper.getExternalContactByAppKey(appKey);
    }

    //
    @Override
    public R deleteQwSopLogsByJsApi(GetQwSopLogsByJsApiParam param) {

        try {
            logger.info("删除或拉黑-处理营期-"+param.getQwUserId()+"|"+param.getCorpId()+"|"+param.getExternalUserId());

            //修改客户状态
            QwExternalContact contact = new QwExternalContact();
            contact.setStatus(7);
            contact.setUserId(param.getQwUserId());
            contact.setCorpId(param.getCorpId());
            contact.setExternalUserId(param.getExternalUserId());
            qwExternalContactMapper.updateQwExternalContactByUseridBlock(contact);


            //删除营期
            sopUserLogsInfoMapper.deleteByQwUserIdAndCorpIdToContactId(param.getQwUserId(), param.getCorpId(), param.getExternalUserId());

            //删除待发送记录
            qwSopLogsMapper.updateQwSopLogsByDeleted(param);


            return  R.ok();
        }catch (Exception e){
            return R.error();
        }


    }

    public void batchInsertQwSopLogs(List<QwSopLogs> logsToInsert) {
        if(logsToInsert == null || logsToInsert.isEmpty()) return;
        qwSopLogsMapper.batchInsertQwSopLogs(logsToInsert);
    }

    @Override
    public List<QwSopLogsDoSendListTVO> expiredMessagesByQwSopLogs() {
        return qwSopLogsMapper.getExpiredMessagesByQwSopLogs();
    }



    // 定义一个方法来批量处理插入逻辑，支持每 500 条数据一次的批量插入
    private void processAndInsertQwSopLogs(List<QwSopLogsDoSendListTVO> logsByJsApiNotExtId) {
        // 定义批量插入的大小
        int batchSize = 500;

        // 循环处理外部用户 ID，每次处理批量大小的子集
        for (int i = 0; i < logsByJsApiNotExtId.size(); i += batchSize) {

            int endIndex = Math.min(i + batchSize, logsByJsApiNotExtId.size());
            List<QwSopLogsDoSendListTVO> batchList = logsByJsApiNotExtId.subList(i, endIndex);  // 获取当前批次的子集

            // 直接使用批次数据进行批量更新，不需要额外的 List
            try {
                qwSopLogsMapper.batchUpdateQwSopLogsBySendTime(batchList);
            } catch (Exception e) {
                // 记录异常日志，方便后续排查问题
                logger.error("批量更新数据时发生异常，处理的批次起始索引为: " + i, e);
            }
        }
    }

    // 定义一个方法来批量处理插入逻辑，支持每 500 条数据一次的批量插入
    private void processAndInsertQwSopLogsByTakeRecordsList(List<QwSopLogsDoSendListTVO> logsByJsApi ) {
        // 定义批量插入的大小
        int batchSize = 500;

        // 循环处理外部用户 ID，每次处理批量大小的子集
        for (int i = 0; i < logsByJsApi.size(); i += batchSize) {

            int endIndex = Math.min(i + batchSize, logsByJsApi.size());
            List<QwSopLogsDoSendListTVO> batchList = logsByJsApi.subList(i, endIndex);  // 获取当前批次的子集

            // 直接使用批次数据进行批量更新，不需要额外的 List
            try {
                qwSopLogsMapper.batchUpdateQwSopLogsByTakeRecordsList(batchList);
            } catch (Exception e) {
                // 记录异常日志，方便后续排查问题
                logger.error("批量更新数据时发生异常，处理的批次起始索引为: " + i, e);
            }
        }
    }

    /**
     * 创建企业群发消息
     * 该方法负责处理企业微信的群发消息创建和发送
     */
    @Override
    public void createCorpMassSending(String date) {
        long startTime = System.currentTimeMillis();
        logger.info("开始执行企业微信群发消息创建任务");

        // 获取需要发送的SOP日志记录
        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.selectSopLogsByCreateCorpMassSending(date);
//        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.checkQwSopLogs();
        if (qwSopLogs.isEmpty()) {
            logger.error("zyp \n【企微官方群发记录为空】");
            return;
        }

        // 按照企业员工ID、发送时间、SOP ID和企业ID进行分组
        Map<String, List<QwSopLogs>> groupedLogs = new HashMap<>();
        for (QwSopLogs log : qwSopLogs) {
            String key = log.getQwUserid() + "|" + log.getSendTime() + "|" + log.getSopId() + "|" + log.getCorpId();
            groupedLogs.computeIfAbsent(key, k -> new ArrayList<>()).add(log);
        }

        // 创建线程池，使用固定大小的线程池以避免过多线程导致的资源竞争
        int threadCount = Math.min(10, Runtime.getRuntime().availableProcessors() + 1);
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        // 创建用于发送消息的嵌套线程池
        ExecutorService messageExecutorService = Executors.newFixedThreadPool(20);

        // 用于存储需要批量更新的日志记录，使用线程安全的集合
        List<QwSopLogs> updateList = Collections.synchronizedList(new ArrayList<>());

        // 使用CountDownLatch等待所有任务完成
        CountDownLatch latch = new CountDownLatch(groupedLogs.size());

        // 处理每个分组
        for (Map.Entry<String, List<QwSopLogs>> entry : groupedLogs.entrySet()) {
            String key = entry.getKey();
            List<QwSopLogs> logs = entry.getValue();
            String[] keys = key.split("\\|");
            String qwUserid = keys[0];
            String corpId = keys[3];

//            QwUser qwUser = qwUserMapper.selectQwUserByCorpIdAndUserId(corpId, qwUserid);
            // 查询员工信息的id
            QwUser qwUser = qwExternalContactService.getQwUserByRedis(corpId.trim(),qwUserid.trim());
            if (qwUser != null && qwUser.getIsDel() == 0) {
                // 提交到线程池处理每个分组
                executorService.submit(() -> {
                    try {
                        // 按外部用户ID分组
                        Map<String, List<QwSopLogs>> userLogsMap = new HashMap<>();
                        for (QwSopLogs log : logs) {
                            String externalUserId = log.getExternalUserId();
                            userLogsMap.computeIfAbsent(externalUserId, k -> new ArrayList<>()).add(log);
                        }

                        // 使用嵌套的CountDownLatch等待所有消息发送完成
                        CountDownLatch messageLatch = new CountDownLatch(userLogsMap.size());

                        // 处理每个外部用户
                        for (Map.Entry<String, List<QwSopLogs>> userEntry : userLogsMap.entrySet()) {
                            String externalUserId = userEntry.getKey();
                            List<QwSopLogs> userLogs = userEntry.getValue();

                            // 提交到消息发送线程池
                            messageExecutorService.submit(() -> {
                                try {
                                    QwMsgTemplateSop templateSop = new QwMsgTemplateSop();
                                    templateSop.setChatType("single");
                                    templateSop.setAllowSelect(false);
                                    templateSop.setSender(qwUserid);
                                    templateSop.setExternalUseridList(Collections.singletonList(externalUserId));

                                    List<QwMsgTemplateSop.Attachment> attachments = new ArrayList<>();
                                    boolean hasError = false;

                                    for (QwSopLogs log : userLogs) {
                                        try {
                                            QwSopTempSetting.Content content = JSON.parseObject(log.getContentJson(), QwSopTempSetting.Content.class);
                                            if (content == null || content.getSetting() == null) continue;
                                            Long courseId = content.getCourseId();
                                            for (QwSopTempSetting.Content.Setting set : content.getSetting()) {
                                                processContent(set, corpId, templateSop, attachments, courseId);
                                            }
                                        } catch (Exception e) {
                                            logger.error("消息内容解析失败，logId：{}", log.getId(), e);
                                            hasError = true;
                                        }
                                    }

                                    if (!hasError && (!attachments.isEmpty() || templateSop.getTextContent() != null)) {
                                        templateSop.setAttachments(attachments);
                                        try {
                                            QwAddMsgTemplateResult result = qwApiService.addMsgTemplateBySop(templateSop, corpId);
                                            for (QwSopLogs log : userLogs) {
                                                log.setSendStatus(result.getErrCode() == 0 || result.getErrCode() == 41063 ? 1L : 0L);
                                                log.setMsgId(result.getMsgId());
                                                updateList.add(log);
                                            }
                                            if (result.getErrCode() != 0 && result.getErrCode() != 41063){
                                                logger.error("企业微信接口-消息发送失败，corpId：{}，errCode：{}，errMsg：{}", corpId, result.getErrCode(), result.getErrMsg());
                                            }
                                        } catch (Exception e) {
                                            logger.error("消息发送失败，user：{}", externalUserId, e);
                                            for (QwSopLogs log : userLogs) {
                                                log.setSendStatus(0L);
                                                updateList.add(log);
                                            }
                                        }
                                    }
                                } finally {
                                    messageLatch.countDown();
                                }
                            });
                        }

                        // 等待所有消息发送完成
                        try {
                            messageLatch.await();
                        } catch (InterruptedException e) {
                            logger.error("等待消息发送完成时被中断", e);
                            Thread.currentThread().interrupt();
                        }
                    } finally {
                        latch.countDown();
                    }
                });
            }else {
                logger.error("官方群发 员工信息有误："+corpId+":"+qwUserid);
            }

        }

        // 等待所有分组处理完成
        try {
            latch.await();
        } catch (InterruptedException e) {
            logger.error("等待分组处理完成时被中断", e);
            Thread.currentThread().interrupt();
        }

        // 批量更新发送状态，每500条一批
        if (!updateList.isEmpty()) {
            int batchSize = 500;
            for (int i = 0; i < updateList.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, updateList.size());
                List<QwSopLogs> batch = updateList.subList(i, endIndex);
                try {
                    qwSopLogsMapper.batchUpdateStatus(batch);
                    logger.info("批量修改 sopLogs 成功，修改数量: " + batch.size());
                } catch (Exception e) {
                    logger.error("批量修改 sopLogs 失败", e);
                }
            }
        }

        // 关闭线程池
        executorService.shutdown();
        messageExecutorService.shutdown();

        long endTime = System.currentTimeMillis();
        logger.info("企业微信群发消息创建任务执行完成，总耗时: {} 毫秒", (endTime - startTime));
    }

    // 处理不同类型的内容
    private void processContent(QwSopTempSetting.Content.Setting set, String corpId,
                                QwMsgTemplateSop templateSop, List<QwMsgTemplateSop.Attachment> attachments,Long courseId) {
        switch (set.getContentType()) {
            case "1":
                templateSop.setTextContent(set.getValue());
                break;
            case "2":
                handleImageAttachment(set, corpId, attachments);
                break;
            case "3":
                handleLinkAttachment(set, corpId, attachments);
                break;
            case "4":
                handleMiniProgramAttachment(set, corpId, attachments,courseId);
                break;
        }
    }

    // 处理图片附件
    private void handleImageAttachment(QwSopTempSetting.Content.Setting set, String corpId,
                                       List<QwMsgTemplateSop.Attachment> attachments) {
        if (StringUtils.isNotEmpty(set.getImgUrl())) {
            try {
                QwUploadImgResult result = qwApiService.uploadimgs(set.getImgUrl(), corpId);
                if (result.getErrcode() == 0) {
                    QwMsgTemplateSop.Attachment attachment = new QwMsgTemplateSop.Attachment();
                    attachment.setType(2);
                    attachment.setImagePicUrl(result.getUrl());
                    attachments.add(attachment);
                }
            } catch (Exception e) {
                logger.error("图片上传失败", e);
            }
        }
    }

    // 处理链接附件
    private void handleLinkAttachment(QwSopTempSetting.Content.Setting set, String corpId,
                                      List<QwMsgTemplateSop.Attachment> attachments) {
        if (StringUtils.isNotEmpty(set.getLinkImageUrl())) {
            try {
//                QwUploadImgResult result = qwApiService.uploadimgs(set.getLinkImageUrl(), corpId);
//                if (result.getErrcode() == 0) {
                    QwMsgTemplateSop.Attachment attachment = new QwMsgTemplateSop.Attachment();
                    attachment.setType(3);
                    attachment.setLinkTitle(set.getLinkTitle());
                    attachment.setLinkPicurl(set.getLinkImageUrl());
                    attachment.setLinkDesc(set.getLinkDescribe());
                    attachment.setLinkUrl(set.getLinkUrl());
                    attachments.add(attachment);
//                }
            } catch (Exception e) {
                logger.error("链接图片上传失败", e);
            }
        }
    }

    private void handleMiniProgramAttachment(QwSopTempSetting.Content.Setting set, String corpId, List<QwMsgTemplateSop.Attachment> attachments,Long courseId) {
        if (StringUtils.isNotEmpty(set.getMiniprogramPage())) {
            try {
                String key = String.format("miniprogram:%s:%s", corpId, courseId);
                String mediaId = redisCache.getCacheObject(key);

                if (StringUtils.isNotEmpty(mediaId)) {

                    QwMsgTemplateSop.Attachment attachment = new QwMsgTemplateSop.Attachment();
                    attachment.setType(4);
//                    attachment.setMiniProgramTitle(set.getMiniprogramTitle());
                    //强制限制
                    String title = set.getMiniprogramTitle() != null ? set.getMiniprogramTitle() : "";
                    int maxLength = 20;
                    attachment.setMiniProgramTitle(title.length() > maxLength ? title.substring(0, maxLength) : title);

                    attachment.setMiniProgramPicMediaId(mediaId);
                    attachment.setMiniProgramAppId(set.getMiniprogramAppid());
                    attachment.setMiniProgramPage(set.getMiniprogramPage());
                    attachments.add(attachment);
                } else {
                    logger.error("未找到小程序图片mediaId, corpId:{}, courseId:{}", corpId, courseId);
                }
            } catch (Exception e) {
                logger.error("获取小程序图片mediaId失败", e);
            }
        }
    }



}
