package com.fs.sop.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fs.common.config.FSSysConfig;
import com.fs.common.core.domain.R;
import com.fs.common.exception.base.BaseException;
import com.fs.common.utils.PubFun;
import com.fs.common.utils.StringUtils;
import com.fs.common.utils.date.DateUtil;
import com.fs.company.domain.Company;
import com.fs.company.domain.CompanyMiniapp;
import com.fs.company.mapper.CompanyMapper;
import com.fs.company.mapper.CompanyUserMapper;
import com.fs.company.service.ICompanyMiniappService;
import com.fs.config.cloud.CloudHostProper;
import com.fs.course.config.CourseConfig;
import com.fs.course.domain.FsCourseDomainName;
import com.fs.course.domain.FsCourseLink;
import com.fs.course.domain.FsCourseRealLink;
import com.fs.course.domain.FsCourseWatchLog;
import com.fs.course.mapper.FsCourseDomainNameMapper;
import com.fs.course.mapper.FsCourseLinkMapper;
import com.fs.course.mapper.FsCourseWatchLogMapper;
import com.fs.course.param.FsCourseLinkCreateParam;
import com.fs.course.service.IFsCourseLinkService;
import com.fs.course.service.IFsUserCourseVideoService;
import com.fs.fastGpt.domain.FastGptChatReplaceWords;
import com.fs.fastGpt.mapper.FastGptChatReplaceWordsMapper;
import com.fs.qw.domain.*;
import com.fs.qw.mapper.*;
import com.fs.qw.param.QwExtCourseSopWatchLog;
import com.fs.qw.param.QwExternalContactVOTime;
import com.fs.qw.param.QwTagSearchParam;
import com.fs.qw.service.IQwCompanyService;
import com.fs.qw.service.impl.AsyncSopTestService;
import com.fs.qw.service.impl.QwExternalContactServiceImpl;
import com.fs.qw.vo.GroupUserExternalVo;
import com.fs.qw.vo.QwSopCourseFinishTempSetting;
import com.fs.qw.vo.QwSopRuleTimeVO;
import com.fs.qw.vo.QwTagGroupListVO;
import com.fs.sop.domain.*;
import com.fs.sop.mapper.QwSopLogsMapper;
import com.fs.sop.mapper.QwSopMapper;
import com.fs.sop.mapper.SopUserLogsInfoMapper;
import com.fs.sop.mapper.SopUserLogsMapper;
import com.fs.sop.params.BatchSopUserLogsInfoParam;
import com.fs.sop.params.BatchSopUserLogsInfoParamU;
import com.fs.sop.params.SendUserLogsInfoMsgParam;
import com.fs.sop.params.SopUserLogsParamByDate;
import com.fs.sop.service.IQwSopService;
import com.fs.sop.service.IQwSopTempVoiceService;
import com.fs.sop.service.ISopUserLogsInfoService;
import com.fs.sop.service.ISopUserLogsService;
import com.fs.sop.vo.ExtCourseSopWatchLogVO;
import com.fs.sop.vo.QwCreateLinkByAppVO;
import com.fs.sop.vo.SopUserLogsInfoVOE;
import com.fs.sop.vo.SopUserLogsVo;
import com.fs.system.service.ISysConfigService;
import com.fs.voice.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.ConstraintViolationException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.fs.course.utils.LinkUtil.generateRandomStringWithLock;

@Service
public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {

    private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
    private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
    private static final String miniappRealLink = "/pages_course/video.html?course=";
    private static final String appRealLink = "/pages/courseAnswer/index?link=";
    private static final String appLink = "https://jump.ylrztop.com/jumpapp/pages/index/index?link=";
//    private static final String miniappRealLink = "/pages/index/index?course=";

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private FsCourseDomainNameMapper fsCourseDomainNameMapper;

    private static final Logger log = LoggerFactory.getLogger(SopUserLogsInfoServiceImpl.class);
    @Autowired
    private SopUserLogsInfoMapper sopUserLogsInfoMapper;

    @Autowired
    private FsCourseLinkMapper fsCourseLinkMapper;
    @Autowired
    private QwGroupChatMapper qwGroupChatMapper;

    @Autowired
    private FastGptChatReplaceWordsMapper fastGptChatReplaceWordsMapper;
    @Autowired
    private IFsCourseLinkService courseLinkService;

    @Autowired
    private SopUserLogsMapper sopUserLogsMapper;

    @Autowired
    private IQwSopService qwSopService;

    @Autowired
    private QwUserMapper qwUserMapper;

    @Autowired
    private QwSopMapper qwSopMapper;

    @Autowired
    private QwSopLogsMapper qwSopLogsMapper;

    @Autowired
    private ISopUserLogsService sopUserLogsService;

    @Autowired
    private FsCourseWatchLogMapper fsCourseWatchLogMapper;

    @Autowired
    private AsyncSopTestService asyncSopTestService;

    @Autowired
    private IFsCourseLinkService fsCourseLinkService;
    @Autowired
    private QwTagMapper qwTagMapper;

    @Autowired
    private QwExternalContactMapper qwExternalContactMapper;

    @Autowired
    private QwExternalContactServiceImpl qwExternalContactService;

    @Autowired
    private IQwCompanyService iQwCompanyService;

    @Autowired
    private IFsUserCourseVideoService iFsUserCourseVideoService;


    @Autowired
    private CompanyUserMapper companyUserMapper;
    @Autowired
    private QwGroupChatUserMapper qwGroupChatUserMapper;

    @Autowired
    private ICompanyMiniappService companyMiniappService;
    @Autowired
    private CloudHostProper cloudHostProper;

    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private IQwSopTempVoiceService sopTempVoiceService;



    @Override
    public void save(SopUserLogsInfo sopUserLogsInfo) {
        sopUserLogsInfoMapper.insertSopUserLogsInfo(sopUserLogsInfo);
    }

    @Override
    public void update(SopUserLogsInfo info) {
        sopUserLogsInfoMapper.updateById(info);
    }

    @Override
    public void updateSopUserInfoByExternalId(Long qwExternalId, Long userId) {
        sopUserLogsInfoMapper.updateQwExternalContactChangeUserId(qwExternalId,userId);
    }

    @Override
    public SopUserLogsInfo getById(String id) {
        return sopUserLogsInfoMapper.selectById(id);
    }

    @Override
    public List<SopUserLogsInfo> getAll() {
        return sopUserLogsInfoMapper.selectAll();
    }

    @Override
    public void deleteById(String id) {
        sopUserLogsInfoMapper.deleteById(id);
    }

    @Override
    public int deleteSopUserLogsInfoByIds(String[] ids) {

        List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoByIds(ids);
        List<Map<String, Object>> result = sopUserLogsInfos.stream()
                .map(info -> {
                    Map<String, Object> fields = new HashMap<>();
                    fields.put("sopId", info.getSopId());
                    fields.put("exterId", info.getExternalContactId());
                    fields.put("qwUserId", info.getQwUserId());
                    fields.put("cropId", info.getCorpId());
                    return fields;
                })
                .collect(Collectors.toList());
        log.info("删除客户营期-"+result);

        return sopUserLogsInfoMapper.deleteSopUserLogsInfoByIds(ids);
    }

    @Override
    public List<SopUserLogsInfo> selectSopUserLogsInfoList(SopUserLogsInfo info) {

        return sopUserLogsInfoMapper.selectSopUserLogsInfoList(info);
    }
    @Override
    public List<SopUserLogsInfoVOE> selectSopUserLogsInfoListVO(SopUserLogsInfo info) {
        return  sopUserLogsInfoMapper.selectSopUserLogsInfoListVO(info);
    }


    @Override
    public void batchInsertSopUserLogsInfo(List<SopUserLogsInfo> logsToInsert) {
        sopUserLogsInfoMapper.batchInsertSopUserLogsInfo(logsToInsert);
    }

    @Override
    public void batchUpdateSopUserLogsInfoByMoreStudy(List<QwExternalContact> contactList) {
        sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoByMoreStudy(contactList);
    }

    @Override
    public void batchUpdateSopUserLogsInfoByIsDaysNotStudy(List<QwExternalContact> contactList) {
        sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoByIsDaysNotStudy(contactList);
    }

    @Override
    public void batchUpdateSopUserLogsInfoByLevel(List<QwExternalContact> contactList) {
        sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoByLevel(contactList);
    }

    @Override
    public void insertSopUserLogsInfo(SopUserLogsInfo logsToInsert) {
        sopUserLogsInfoMapper.insertSopUserLogsInfo(logsToInsert);
    }

    /**
     * 查询sopUserLogsInfo
     *
     * @param id sopUserLogsInfo主键
     * @return sopUserLogsInfo
     */
    @Override
    public SopUserLogsInfo selectSopUserLogsInfoById(String id)
    {
        return sopUserLogsInfoMapper.selectSopUserLogsInfoById(id);
    }

    /**
     * 修改sopUserLogsInfo
     *
     * @param logsInfo sopUserLogsInfo
     * @return 结果
     */
    @Override
    public R updateSopUserLogsInfoToTime(SopUserLogsInfo logsInfo)
    {


        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            logsInfo.setUpdateTime(sdf.format(new Date()));

            //用于查询
            SopUserLogs userLogs=new SopUserLogs();
            userLogs.setSopId(logsInfo.getSopId());
            userLogs.setQwUserId(logsInfo.getQwUserId());
            userLogs.setCorpId(logsInfo.getCorpId());
            userLogs.setStatus(1);
            userLogs.setStartTime(logsInfo.getCreateTime());

            String  unionSopStartId = sopUserLogsService.selectSopUserLogsByUpdate(userLogs);


            SopUserLogsInfo sopUserLogsInfo=new SopUserLogsInfo();
            sopUserLogsInfo.setId(logsInfo.getId());
            sopUserLogsInfo.setQwUserId(logsInfo.getQwUserId());
            sopUserLogsInfo.setCorpId(logsInfo.getCorpId());
            sopUserLogsInfo.setExternalContactId(logsInfo.getExternalContactId());
            sopUserLogsInfo.setExternalId(logsInfo.getExternalId());
            sopUserLogsInfo.setSopId(logsInfo.getSopId());
            sopUserLogsInfo.setExternalUserName(logsInfo.getExternalUserName());
            sopUserLogsInfo.setCreateTime(logsInfo.getCreateTime());
            sopUserLogsInfo.setUpdateTime(sdf.format(new Date()));
            sopUserLogsInfo.setCrtTime(logsInfo.getCrtTime());

            //查询sop任务开始时间营期表 是否有这个营期
            if (!StringUtil.strIsNullOrEmpty(unionSopStartId)){
                //有这个营期，则更新
                sopUserLogsInfo.setUserLogsId(unionSopStartId);

                int i = sopUserLogsInfoMapper.updateSopUserLogsInfoToTime(sopUserLogsInfo);


            } else {
                //如果查不出来营期 ，则新建营期
                //查询sop的模板id
                QwSop qwSop = qwSopService.selectQwSopById(logsInfo.getSopId());

                //查询这个sop任务的员工的信息
                QwUser qwUser = qwUserMapper.selectQwUserByQwUseridAndCorpId(logsInfo.getQwUserId(), logsInfo.getCorpId());

                SopUserLogsParamByDate userLogsParamByDate = new SopUserLogsParamByDate();
                userLogsParamByDate.setSopId(logsInfo.getSopId());
                userLogsParamByDate.setSopTempId(qwSop.getTempId());
                userLogsParamByDate.setQwUserId(logsInfo.getQwUserId());
                userLogsParamByDate.setCorpId(logsInfo.getCorpId());
                userLogsParamByDate.setStartTime(logsInfo.getCreateTime());
                userLogsParamByDate.setStatus(1);
                userLogsParamByDate.setUserId(qwUser.getId()+"|"+qwUser.getCompanyUserId()+"|"+qwUser.getCompanyId());

                //如果没有这个营期没有就先插入
                sopUserLogsService.insertSopUserLogsByDate(userLogsParamByDate);

                userLogs.setSopTempId(qwSop.getTempId());
                //获取新的
                String  unionSopStartIdNew = sopUserLogsService.selectSopUserLogsByUnionSopId(userLogs);

                sopUserLogsInfo.setUserLogsId(unionSopStartIdNew);
                sopUserLogsInfo.setId(logsInfo.getId());
                int i = sopUserLogsInfoMapper.updateSopUserLogsInfoToTime(sopUserLogsInfo);

            }
        }catch (Exception e){
            return R.error().put("msg","修改营期失败："+e.getMessage());
        }

        return R.ok();
    }

    @Override
    public R batchUpdateSopUserLogsInfoToTime(BatchSopUserLogsInfoParam param) {

        try {

                //用于查询
                SopUserLogs userLogs=new SopUserLogs();
                userLogs.setSopId(param.getSopId());
                userLogs.setQwUserId(param.getQwUserId());
                userLogs.setCorpId(param.getCorpId());
                userLogs.setStatus(1);
                userLogs.setStartTime(param.getParamTime());

                String  unionSopStartId = sopUserLogsService.selectSopUserLogsByUpdate(userLogs);

                 BatchSopUserLogsInfoParamU infoParamU=new BatchSopUserLogsInfoParamU();
                    infoParamU.setIds(param.getIds());
                //查询sop任务开始时间营期表 是否有这个营期
                if (!StringUtil.strIsNullOrEmpty(unionSopStartId)){
                    infoParamU.setUserLogsId(unionSopStartId);
                    if (param.getIds().length>0){
                        batchUpdateSopUserLogsInfoToTime(infoParamU);
                    }

                }
                else {
                    //如果查不出来营期 ，则新建营期
                    //查询sop的模板id
                    QwSop qwSop = qwSopService.selectQwSopById(param.getSopId());

                    //查询这个sop任务的员工的信息
                    QwUser qwUser = qwUserMapper.selectQwUserByQwUseridAndCorpId(param.getQwUserId(), param.getCorpId());

                    SopUserLogsParamByDate userLogsParamByDate = new SopUserLogsParamByDate();
                    userLogsParamByDate.setSopId(param.getSopId());
                    userLogsParamByDate.setSopTempId(qwSop.getTempId());
                    userLogsParamByDate.setQwUserId(param.getQwUserId());
                    userLogsParamByDate.setCorpId(param.getCorpId());
                    userLogsParamByDate.setStartTime(param.getParamTime());
                    userLogsParamByDate.setStatus(1);
                    userLogsParamByDate.setUserId(qwUser.getId()+"|"+qwUser.getCompanyUserId()+"|"+qwUser.getCompanyId());

                    //如果没有这个营期没有就先插入
                    int i1 = sopUserLogsService.insertSopUserLogsByDate(userLogsParamByDate);
                    if (i1>0){
                        userLogs.setSopTempId(qwSop.getTempId());
                        //获取新的
                        String  unionSopStartIdNew = sopUserLogsService.selectSopUserLogsByUnionSopId(userLogs);
                        infoParamU.setUserLogsId(unionSopStartIdNew);

                        if (param.getIds().length>0){
                            batchUpdateSopUserLogsInfoToTime(infoParamU);
                        }

                    }



                }
            } catch (ConstraintViolationException e) {
                return R.error().put("msg", "修改营期失败：目标营期已经有此客户，请检查客户信息 是否重复，重复请联系超管 删除此营期数据");
            } catch (Exception e) {
                return R.error().put("msg", "修改营期失败：" + e.getMessage());
        }

        return R.ok();
    }


    public void batchUpdateSopUserLogsInfoToTime(BatchSopUserLogsInfoParamU paramU) {
        // 定义每批次的大小
        int batchSize = 200;
        String[] ids = paramU.getIds();

        for (int i = 0; i < ids.length; i += batchSize) {
            // 计算当前批次的结束索引
            int end = Math.min(i + batchSize, ids.length);

            // 拆分当前批次数据
            String[] batchIds = Arrays.copyOfRange(ids, i, end);

            // 创建新的参数对象
            BatchSopUserLogsInfoParamU batchParam = new BatchSopUserLogsInfoParamU();
            batchParam.setIds(batchIds);
            batchParam.setUserLogsId(paramU.getUserLogsId());

            // 执行批量更新
            sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoToTime(batchParam);
        }
    }

    private QwSopLogs createBaseLog(String formattedSendTime, SopUserLogsVo logVo,
                                    QwSopRuleTimeVO ruleTimeVO, String externalContactId,
                                    String externalUserName, Long fsUserId, Integer isOfficial,
                                    Long externalId) {
        QwSopLogs sopLogs = new QwSopLogs();
        sopLogs.setSendTime(formattedSendTime);
        sopLogs.setQwUserid(logVo.getQwUserId());
        sopLogs.setCorpId(logVo.getCorpId());
        sopLogs.setLogType(ruleTimeVO.getType());

        sopLogs.setSendType(isOfficial == 1 ? 1 : ruleTimeVO.getSendType());


        sopLogs.setSendStatus(3L);
        sopLogs.setReceivingStatus(0L);

        String[] userKey = logVo.getUserId().split("\\|");
        sopLogs.setCompanyId(Long.valueOf(userKey[2].trim()));
        sopLogs.setSopId(logVo.getSopId());

        sopLogs.setExternalUserId(externalContactId);
        sopLogs.setExternalId(externalId);
        sopLogs.setExternalUserName(externalUserName);
        sopLogs.setFsUserId(fsUserId);

        return sopLogs;
    }
    @Override
    public R sendUserLogsInfoMsg(SendUserLogsInfoMsgParam param) {
        QwSop qwSop = qwSopMapper.selectQwSopById(param.getSopId());
        List<FastGptChatReplaceWords> words = fastGptChatReplaceWordsMapper.selectAllFastGptChatReplaceWords();
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
        Date createTime=new Date();
        if (config == null) {
            return R.error().put("msg","课程默认配置为空，请联系管理员");
        }

        if (StringUtil.strIsNullOrEmpty(param.getCorpId())){
            return R.error().put("msg","企业编号为空，不能创建一键群发");
        }


        // 查询公司关联小程序数据
        List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));

        Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));
        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(param.getCorpId());
        if (qwCompany == null ) {
            return  R.error().put("msg","企业不存在，请联系管理员");
        }
        List<QwSopLogs> sopLogsList;
        if(param.getFilterMode() != null && param.getFilterMode() == 2 && param.getChatIds() != null && param.getChatIds().length > 0){
            List<QwGroupChat> groupList = qwGroupChatMapper.selectQwGroupChatByChatIds(param.getChatIds());

            Map<String, QwGroupChat> groupMap = PubFun.listToMapByGroupObject(groupList, QwGroupChat::getChatId);
            List<QwGroupChatUser> groupUserList = qwGroupChatUserMapper.selectQwGroupChatUserByChatIds(groupList.stream().map(QwGroupChat::getChatId).toArray(String[]::new));
            Map<String, List<QwGroupChatUser>> groupUserMap = PubFun.listToMapByGroupList(groupUserList, QwGroupChatUser::getChatId);
            groupList.stream().filter(e -> groupUserMap.containsKey(e.getChatId())).forEach(e -> {
                e.setChatUserList(groupUserMap.get(e.getChatId()));
            });
            List<String> groupChatUserIds = PubFun.listToNewList(groupUserList, QwGroupChatUser::getUserId);
            if (!groupChatUserIds.isEmpty()) {
                List<GroupUserExternalVo> userList = qwExternalContactMapper.selectByGroupUser(groupChatUserIds);
                Map<String, List<GroupUserExternalVo>> userMap = PubFun.listToMapByGroupList(userList, GroupUserExternalVo::getExternalUserId);
                groupUserList.forEach(e -> {
                    e.setUserList(userMap.getOrDefault(e.getUserId(), Collections.emptyList()));
                });
            }
            try {
                groupList.forEach(groupChat -> {
                    QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText2(groupChat.getOwner(), groupChat.getCorpId());
                    groupChat.getChatUserList().stream().filter(e -> e.getUserList() != null && !e.getUserList().isEmpty()).forEach(e -> {
                        Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(e.getUserList(), GroupUserExternalVo::getUserId);
                        GroupUserExternalVo vo = userMap.get(groupChat.getOwner());
                        if (vo != null && vo.getId() != null) {
                            addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(), vo.getFsUserId(), qwUser.getId().toString(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), vo.getId(), param.getStartTime(), createTime);
                        }
                    });
                });
            } catch (Exception e) {
                log.error("群聊创建看课记录失败！", e);
            }
            if (param.getSendType() != null && param.getSendType() == 2) {
                sopLogsList = groupUserList.stream().map(groupUser -> {
                    QwGroupChat qwGroupChat = groupMap.get(groupUser.getChatId());

                    QwUser qwUser = qwExternalContactService.getQwUserByRedis(qwGroupChat.getCorpId(),qwGroupChat.getOwner());
                    if (qwUser==null){
                        throw new BaseException("企业微信用户不存在:" + qwGroupChat.getOwner());
                    }

//                    QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText2(qwGroupChat.getOwner(), qwGroupChat.getCorpId());
//                    if (qwUser == null) {
//                        throw new BaseException("企业微信用户不存在:" + qwGroupChat.getOwner());
//                    }
                    Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(groupUser.getUserList(), GroupUserExternalVo::getUserId);
                    GroupUserExternalVo vo = userMap.get(qwGroupChat.getOwner());
                    if (vo == null) return null;
                    QwSopLogs sopLogs = new QwSopLogs();

                    sopLogs.setQwUserid(qwUser.getQwUserId());
                    sopLogs.setExternalUserId(vo.getExternalUserId());
                    sopLogs.setLogType(2);
                    sopLogs.setContentJson(param.getSetting());
                    sopLogs.setSendStatus(3L);
                    sopLogs.setSendTime(DateUtil.formatLocalDateTime(LocalDateTime.now()));
                    sopLogs.setCompanyId(qwSop.getCompanyId());
                    sopLogs.setReceivingStatus(0L);
                    sopLogs.setSopId(param.getSopId());
                    sopLogs.setCorpId(qwGroupChat.getCorpId());
                    sopLogs.setSort(30000001);
                    sopLogs.setSendType(2);
                    sopLogs.setExternalUserName(groupUser.getName());
                    sopLogs.setQwUserKey(qwUser.getId());

                    // 设置实际发送人
                    updateQwUserKey(sopLogs,qwUser.getQwUserId(),param.getSopId(),groupUser.getChatId());
                    //域名
                    String companyUserId = qwUser.getCompanyUserId().toString();
                    String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
                    if (StringUtils.isEmpty(domainName)) {
                        domainName = config.getRealLinkDomainName();
                    }
                    QwSopCourseFinishTempSetting setting = new QwSopCourseFinishTempSetting();
                    List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(), QwSopCourseFinishTempSetting.Setting.class);
                    for (QwSopCourseFinishTempSetting.Setting st : list) {

                        //过滤违禁词
                        if ("1".equals(st.getContentType())) {
                            replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
                        }
                        //过滤违禁词
                        if ("3".equals(st.getContentType())) {
                            replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
                            replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
                        }

                        switch (st.getContentType()) {
                            //文字和短链一起
                            case "1":
                            case "3":
//                                if ("1".equals(st.getIsBindUrl())) {
//                                    String qwUserId = qwUser.getQwUserId();
//                                    String companyId = qwUser.getCompanyId().toString();
//                                    Long externalUserId = vo.getId();
////                                    addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(), null, qwUserId, companyUserId, companyId, externalUserId, param.getStartTime(), createTime);
//                                    FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
//                                    createParam.setCourseId(param.getCourseId().longValue());
//                                    createParam.setVideoId(param.getVideoId().longValue());
//                                    createParam.setCorpId(qwSop.getCorpId());
//                                    createParam.setCompanyUserId(Long.parseLong(companyUserId));
//                                    createParam.setCompanyId(Long.parseLong(companyId));
//                                    createParam.setChatId(groupUser.getChatId());
//                                    createParam.setQwUserId(qwUser.getId());
//                                    createParam.setDays(st.getExpiresDays());
//                                    R createLink = courseLinkService.createRoomLinkUrl(createParam);
//                                    if (createLink.get("code").equals(500)) {
//                                        throw new BaseException("链接生成失败！");
//                                    }
//                                    String sortLink = (String) createLink.get("url");
//
//                                    if (StringUtils.isNotEmpty(sortLink)) {
//                                        if ("3".equals(st.getContentType())) {
//                                            st.setLinkUrl(sortLink);
//                                        } else {
//                                            String currentValue = st.getValue();
//                                            if (currentValue == null) {
//                                                st.setValue(sortLink);
//                                            } else {
//                                                st.setValue(currentValue.replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText()) + "\n" + sortLink);
//                                            }
//                                        }
//                                    } else {
//                                        log.warn("生成短链失败，跳过设置 URL。");
//                                    }
//                                }

                                if ("1".equals(st.getContentType())) {
                                    st.setValue(st.getValue()
                                            .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText()));
                                }
                                break;
                            //小程序单独
                            case "4":
                                String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, qwGroupChat.getChatId());

                                String miniAppId = null;

                                int listIndex = 1;
                                if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
                                    Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(qwUser.getCompanyId());
                                    if (integerListMap != null) {
                                        List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);

                                        if (miniapps != null && !miniapps.isEmpty()) {
                                            CompanyMiniapp companyMiniapp = miniapps.get(0);
                                            if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
                                                miniAppId = companyMiniapp.getAppId();
                                            }
                                        }
                                    }
                                }

                                if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
                                    miniAppId = qwCompany.getMiniAppId();
                                }
                                st.setMiniType(listIndex);
                                if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
                                    st.setMiniprogramAppid(miniAppId);
                                } else {
                                    log.error("公司的小程序id为空：采用了前端传的固定值" + sopLogs.getSopId());
                                }

                                st.setMiniprogramPage(linkByMiniApp);
                                break;

                            //语音
                            case "7":
                                createVoiceUrl(st, companyUserId, qwSop);
                                break;
                            //直播小程序单独
                            case "12":
                                String sortLiveLink = "/pages_course/living?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + companyUserId + "&liveId=" + st.getLiveId();
                                st.setContentType("4");
                                String js = configService.selectConfigByKey("his.config");
                                FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
                                st.setMiniprogramAppid(sysConfig.getAppId());
                                st.setMiniprogramPage(sortLiveLink);
                                break;
                        }
                    }
                    setting.setSetting(list);
                    setting.setType(2);
                    setting.setVideoId(param.getVideoId());
                    setting.setCourseId(param.getCourseId());
                    setting.setCourseType(param.getCourseType());
                    sopLogs.setContentJson(JSON.toJSONString(setting));
                    return sopLogs;
                }).filter(Objects::nonNull).collect(Collectors.toList());


            }
            else {
                sopLogsList = groupList.stream().map(groupChat -> {
                    QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText2(groupChat.getOwner(), groupChat.getCorpId());
                    if(qwUser.getCompanyUserId() == null){
                        throw new BaseException("当前企微没绑定员工，无法发送！");
                    }
                    QwSopLogs sopLogs = new QwSopLogs();

                    sopLogs.setQwUserid(qwUser.getQwUserId());
                    sopLogs.setExternalUserId(groupChat.getChatId());
                    sopLogs.setLogType(2);
                    sopLogs.setContentJson(param.getSetting());
                    sopLogs.setSendStatus(3L);
                    sopLogs.setSendTime(DateUtil.formatLocalDateTime(LocalDateTime.now()));
                    sopLogs.setCompanyId(qwSop.getCompanyId());
                    sopLogs.setReceivingStatus(0L);
                    sopLogs.setSopId(param.getSopId());
                    sopLogs.setCorpId(groupChat.getCorpId());
                    sopLogs.setSort(2);
                    sopLogs.setSendType(6);
                    sopLogs.setExternalUserName(groupChat.getName());
                    sopLogs.setQwUserKey(qwUser.getId());
                    // 设置实际发送人
                    updateQwUserKey(sopLogs,qwUser.getQwUserId(),param.getSopId(),groupChat.getChatId());

                    QwSopCourseFinishTempSetting setting = new QwSopCourseFinishTempSetting();

                    List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(), QwSopCourseFinishTempSetting.Setting.class);

                    for (QwSopCourseFinishTempSetting.Setting st : list) {

                        //过滤违禁词
                        if ("1".equals(st.getContentType())) {
                            replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
                        }
                        //过滤违禁词
                        if ("3".equals(st.getContentType())) {
                            replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
                            replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
                        }
                        switch (st.getContentType()) {
                            //文字和短链一起
                            case "1":
                            case "3":
//                                if ("1".equals(st.getIsBindUrl())) {
//                                    FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
//                                    createParam.setCourseId(param.getCourseId().longValue());
//                                    createParam.setVideoId(param.getVideoId().longValue());
//                                    createParam.setCorpId(groupChat.getCorpId());
//                                    createParam.setCompanyUserId(qwUser.getCompanyUserId());
//                                    createParam.setCompanyId(qwUser.getCompanyId());
//                                    createParam.setChatId(groupChat.getChatId());
//                                    createParam.setQwUserId(qwUser.getId());
//                                    createParam.setDays(st.getExpiresDays());
//                                    R createLink = courseLinkService.createRoomLinkUrl(createParam);
//                                    if (createLink.get("code").equals(500)) {
//                                        throw new BaseException("链接生成失败！");
//                                    }
//                                    String link = (String) createLink.get("url");
//                                    if (StringUtils.isNotEmpty(link)) {
//                                        if ("3".equals(st.getContentType())) {
//                                            st.setLinkUrl(link);
//                                        } else {
//                                            String currentValue = st.getValue();
//                                            if (currentValue == null) {
//                                                st.setValue(link);
//                                            } else {
//                                                st.setValue(currentValue
//                                                        .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText())
//                                                        + "\n" + link);
//                                            }
//                                        }
//                                    } else {
//                                        log.error("生成短链失败，跳过设置 URL。");
//                                    }
//                                }
                                if ("1".equals(st.getContentType())) {
                                    st.setValue(st.getValue()
                                            .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText()));
                                }
                                break;
                            //小程序单独
                            case "4":
                                String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, groupChat.getChatId());

                                String miniAppId = null;

                                int listIndex = 1;
                                if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
                                    Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(qwUser.getCompanyId());
                                    if (integerListMap != null) {
                                        List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);

                                        if (miniapps != null && !miniapps.isEmpty()) {
                                            CompanyMiniapp companyMiniapp = miniapps.get(0);
                                            if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
                                                miniAppId = companyMiniapp.getAppId();
                                            }
                                        }
                                    }
                                }

                                if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
                                    miniAppId = qwCompany.getMiniAppId();
                                }
                                st.setMiniType(listIndex);
                                if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
                                    st.setMiniprogramAppid(miniAppId);
                                } else {
                                    log.error("公司的小程序id为空：采用了前端传的固定值" + sopLogs.getSopId());
                                }

                                st.setMiniprogramPage(linkByMiniApp);
                                break;
                            //语音
                            case "7":
                                if (qwUser.getCompanyUserId() != null) {
                                    createVoiceUrl(st, String.valueOf(qwUser.getCompanyUserId()), qwSop);
                                }
                                break;
                            //直播小程序单独
                            case "12":
                                String sortLiveLink = "/pages_course/living?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + qwUser.getCompanyUserId() + "&liveId=" + st.getLiveId();
                                st.setContentType("4");
                                String js = configService.selectConfigByKey("his.config");
                                FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
                                st.setMiniprogramAppid(sysConfig.getAppId());
                                st.setMiniprogramPage(sortLiveLink);
                                break;
                        }
                    }
                    setting.setSetting(list);
                    setting.setType(2);
                    setting.setVideoId(param.getVideoId());
                    setting.setCourseId(param.getCourseId());
                    setting.setCourseType(param.getCourseType());
                    sopLogs.setContentJson(JSON.toJSONString(setting));
                    return sopLogs;
                }).collect(Collectors.toList());
            }
        }else{
            sopLogsList = new ArrayList<>();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoByIds(param.getIds());

            String[] userKey = param.getUserIdParam().split("\\|");

            String qwUserId = userKey[0].trim();

            QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText(Long.valueOf(qwUserId));

            if (qwUser == null) {
                return R.error().put("msg","企业微信用户不存在:"+qwUserId);
            }

            if (qwUser.getCompanyUserId() == null) {
                return R.error().put("msg","企业微信用户不存在未绑定销售-请绑定后重试:"+qwUser.getQwUserName()+"|"+qwUser.getQwUserId());
            }
            if (qwUser.getCompanyId() == null) {
                return R.error().put("msg","企业微信用户不存在未绑定销售公司-请绑定后重试:"+qwUser.getQwUserName()+"|"+qwUser.getQwUserId());
            }

            Company company = companyMapper.selectCompanyById(qwUser.getCompanyId());

            String companyUserId = String.valueOf(qwUser.getCompanyUserId()).trim();
            String companyId = String.valueOf(qwUser.getCompanyId()).trim();

            //域名
//            String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
//            if (StringUtils.isEmpty(domainName)){
//                domainName = config.getRealLinkDomainName();
//            }


            String finalDomainName = "domainName";

            sopUserLogsInfos.forEach(item->{

                QwSopLogs sopLogs=new QwSopLogs();

                sopLogs.setQwUserid(item.getQwUserId());
                sopLogs.setExternalUserId(item.getExternalContactId());
                sopLogs.setExternalId(item.getExternalId());
                sopLogs.setLogType(2);
                sopLogs.setContentJson(param.getSetting());
                sopLogs.setSendStatus(3L);
                sopLogs.setSendTime(sdf.format(new Date()));
                sopLogs.setCompanyId(qwSop.getCompanyId());
                sopLogs.setReceivingStatus(0L);
                sopLogs.setSopId(param.getSopId());
                sopLogs.setCorpId(item.getCorpId());
                sopLogs.setFsUserId(item.getFsUserId());
                sopLogs.setSort(30000000);
                sopLogs.setSendType(5);
                sopLogs.setExternalUserName(item.getExternalUserName());

                QwExternalContact contact = qwExternalContactMapper.selectQwExternalContactByIdForStageStatus(item.getExternalId());

                QwSopCourseFinishTempSetting setting=new    QwSopCourseFinishTempSetting();

                List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
                for (QwSopCourseFinishTempSetting.Setting st : list) {

                    //过滤违禁词
                    if ("1".equals(st.getContentType())){
                        replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
                    }
                    //过滤违禁词
                    if ("3".equals(st.getContentType())){
                        replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
                        replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
                    }

                    switch (st.getContentType()){
                        //文字和短链一起
                        case "1":
                        case "3":
//                            if ("1".equals(st.getIsBindUrl())) {
//
//                                addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
//
//                                String sortLink = generateShortLink(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
//                                        Long.valueOf(qwUserId), companyUserId, companyId, finalDomainName,item.getExternalId(),config);
//
//                                if (StringUtils.isNotEmpty(sortLink)) {
//                                    if ("3".equals(st.getContentType())) {
//                                        st.setLinkUrl(sortLink);
//                                    } else {
//                                        String currentValue = st.getValue();
//                                        if (currentValue == null) {
//                                            st.setValue(sortLink);
//                                        } else {
//                                            st.setValue(currentValue
//                                                    .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
//                                                    .replaceAll("#客户称呼#",StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(contact.getStageStatus())?"同学":contact.getStageStatus())
//                                                    + "\n" + sortLink);
//                                        }
//                                    }
//                                } else {
//                                    log.warn("生成短链失败，跳过设置 URL。");
//                                }
//                            }else {
                                if ("1".equals(st.getContentType())) {
                                    String defaultName = "同学";
                                    if(contact != null && StringUtils.isNotEmpty(contact.getName()) && !"待同步客户".equals(contact.getName())){
                                        defaultName = contact.getName();
                                    }
                                    st.setValue(st.getValue()
                                            .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
                                            .replaceAll("#客户称呼#",contact == null || StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus())?defaultName:contact.getStageStatus()));
                                }
//                            }

                            break;
                        //小程序单独
                        case "4":
                            addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );

                            String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config, null);

                            String miniAppId = null;

                            int effectiveGrade = (item.getGrade() == null) ? 5 : item.getGrade();
                            int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
                            if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
                                Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
                                if (integerListMap != null) {
                                    List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);

                                    if (miniapps != null && !miniapps.isEmpty()) {
                                        CompanyMiniapp companyMiniapp = miniapps.get(0);
                                        if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
                                            miniAppId = companyMiniapp.getAppId();
                                        }
                                    }
                                }
                            }

                            if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
                                miniAppId = qwCompany.getMiniAppId();
                            }
                            st.setMiniType(listIndex);
                            if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
                                st.setMiniprogramAppid(miniAppId);
                            } else {
                                log.error("公司的小程序id为空：采用了前端传的固定值" + sopLogs.getSopId());
                            }


                            st.setMiniprogramPage(linkByMiniApp);

                            break;
                        //语音
                        case "7":
                            createVoiceUrl(st, companyUserId, qwSop);
                            break;
                        //app
                        case "9":
                            addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );

                            QwCreateLinkByAppVO linkByApp = createLinkByApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config,qwUser.getQwUserName(),contact.getFsUserId());
                            st.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
                            st.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));

                            break;
                        //自定义小程序
                        case "10":
                            addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),item.getStartTime(),createTime );
                            if (company!=null){

                                String customMiniAppId = company.getCustomMiniAppId();

                                if (customMiniAppId != null && !customMiniAppId.trim().isEmpty()) {
                                    st.setMiniprogramAppid(customMiniAppId);
                                } else {
                                    st.setMiniprogramAppid("该公司未配置自定义小程序:"+companyId);
                                }
                            }else {
                                st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
                            }

                            break;
                        //直播小程序单独
                        case "12":
                            String sortLiveLink = "/pages_course/living?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + qwUser.getCompanyUserId() + "&liveId=" + st.getLiveId();
                            st.setContentType("4");
                            String js = configService.selectConfigByKey("his.config");
                            FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
                            st.setMiniprogramAppid(sysConfig.getAppId());
                            st.setMiniprogramPage(sortLiveLink);
                            break;
                        default:
                            break;

                    }
                }


                setting.setSetting(list);
                setting.setType(2);
                setting.setVideoId(param.getVideoId());
                setting.setCourseId(param.getCourseId());
                setting.setCourseType(param.getCourseType());

                try {
                    sopLogs.setQwUserKey(Long.valueOf(qwUserId));
                }catch (Exception e){
                    log.error("设置qwUserId异常", e);
                }
                sopLogs.setContentJson(JSON.toJSONString(setting));
                // 设置实际发送人
                updateQwUserKey(sopLogs,qwUser.getQwUserId(),param.getSopId(),null);

                sopLogsList.add(sopLogs);
            });
        }

        //批量插入 发送记录
        if (!sopLogsList.isEmpty()) {
            processAndInsertQwSopLogsBySendMsg(sopLogsList);
        }

        return R.ok();
    }

    private void updateQwUserKey(QwSopLogs sopLogs, String qwUserId, String sopId,String chatId) {
        // 设置实际发送人
        SopUserLogs qwSopLogs = sopUserLogsMapper.queryUserBySopId(qwUserId,sopId,chatId);
        if (qwSopLogs != null && ObjectUtil.isNotEmpty(qwSopLogs.getActualQwId())){
            // sopLogs.setQwUserid(qwUser.getQwUserId());
            sopLogs.setQwUserKey(qwSopLogs.getActualQwId());
        }
    }

    private void createVoiceUrl(QwSopCourseFinishTempSetting.Setting st, String companyUserId, QwSop qwSop) {
        QwSopTempVoice qwSopTempVoice = sopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(Long.valueOf(companyUserId), st.getValue());
        if (qwSopTempVoice != null && qwSopTempVoice.getVoiceUrl() != null && qwSopTempVoice.getRecordType() == 1) {
            st.setVoiceUrl(qwSopTempVoice.getVoiceUrl());
            st.setVoiceDuration(String.valueOf(qwSopTempVoice.getDuration()));
        } else if (qwSopTempVoice == null) {
            if(st.getValue() != null){
                qwSopTempVoice = new QwSopTempVoice();
                qwSopTempVoice.setCompanyUserId(Long.valueOf(companyUserId));
                qwSopTempVoice.setVoiceTxt(st.getValue());
                qwSopTempVoice.setRecordType(0);
                sopTempVoiceService.insertQwSopTempVoice(qwSopTempVoice);
            }
        }
    }


    @Override
    public R sendUserLogsInfoMsgType(SendUserLogsInfoMsgParam param) {
        //营期一键群发
        switch (param.getType()) {
            case 1:
                break;
            case 2:
                processQwSopLogsBySendMsg(param,param.getDraftStrategy());
                log.info("一键群发操作日志2:{}", JSON.toJSONString(param));
                break;
        }

        return null;
    }

    @Override
    public R sendUserLogsInfoMsgSop(SendUserLogsInfoMsgParam param) {
        List<String> sopUserLogsIds = sopUserLogsMapper.getSopUserLogsIds(param);
        if(sopUserLogsIds == null || sopUserLogsIds.isEmpty()){
            throw new BaseException("SOP没有可发送的营期数据");
        }
        String[] ids = sopUserLogsIds.toArray(new String[0]);
        param.setIds(ids);
        log.info("一键群发操作日志1:{}", JSON.toJSONString(param));
        processQwSopLogsBySendMsg(param,param.getDraftStrategy());
        return null;
    }

    @Override
    public List<SopUserLogsInfo> selectRestoreByIsDaysNotStudy(String sopId, String userLogsId) {
        return sopUserLogsInfoMapper.selectRestoreByIsDaysNotStudy(sopId, userLogsId);
    }

    @Override
    public List<ExtCourseSopWatchLogVO> getExtCourseSopWatchLog(QwExtCourseSopWatchLog qwExternalContactId) {


        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSON.parseObject(json, CourseConfig.class);

        List<ExtCourseSopWatchLogVO> watchLogVOList = sopUserLogsInfoMapper.getExtCourseSopWatchLog(qwExternalContactId);

        watchLogVOList.forEach(item->{
            item.setTitle(iFsUserCourseVideoService.selectFsUserCourseVideoByVideoForTitle(item.getVideoId()));
            item.setUrl(config.getSidebarImageUrl());
        });

        return watchLogVOList;
    }

    private R processQwSopLogsBySendMsg(SendUserLogsInfoMsgParam param,Integer draftStrategy) {


        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSON.parseObject(json, CourseConfig.class);

        if (config == null) {
            return R.error("课程默认配置为空，请联系管理员");
        }

        if (StringUtil.strIsNullOrEmpty(param.getCorpId())){
            return R.error("企业编号为空，不能创建一键群发");
        }

        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(param.getCorpId());

        if (qwCompany == null ) {
            return  R.error().put("msg","企业不存在，请联系管理员");
        }

        List<FastGptChatReplaceWords> words = fastGptChatReplaceWordsMapper.selectAllFastGptChatReplaceWords();

        List<SopUserLogsInfo> sopUserLogs = sopUserLogsMapper.selectSopUserLogsByIds(param.getIds());

        // 查询公司关联小程序数据
        List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));
        Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));


        List<Company> companies = companyMapper.selectCompanyAllList();

        //排序
        int sort = 0;
        //发送类型
        int sendType = 0;

        switch (draftStrategy){
            case 1:
                sort=30000000;
                sendType=5;
                break;
            case 2:
                sort=29999999;
                sendType=9;
                break;
            case 3:
                sort=29999999;
                sendType=10;
                break;
        }

        //分组
        Map<AbstractMap.SimpleEntry<String, String>, List<SopUserLogsInfo>> groupedLogs =
                sopUserLogs.stream()
                        .collect(Collectors.groupingBy(
                                log -> new AbstractMap.SimpleEntry<>(log.getQwUserId(), log.getCorpId())
                        ));


        // 遍历分组
        int finalSort = sort;
        int finalSendType = sendType;
        groupedLogs.forEach((key, logs) -> {

            QwUser qwUser = qwUserMapper.selectQwUserByCorpIdAndUserId(key.getValue(), key.getKey());

            if (qwUser == null) {
                log.error("员工信息用户不存在:" + key.getKey()+",企业id:"+key.getValue());
            }else {

                if (qwUser.getCompanyUserId()!=null && qwUser.getCompanyId()!=null){
                    List<QwSopLogs> sopLogsList = processInsertSopUserLogsInfo(logs, qwUser, param, words, config, qwCompany, finalSort,
                            finalSendType,miniMap,companies);

                    //批量插入 发送记录
                    if (!sopLogsList.isEmpty()) {
                        processAndInsertQwSopLogsBySendMsg(sopLogsList);
                    }

                }else {
                    log.error("员工未绑定销售账号 请先绑定 :" + qwUser.getQwUserName()+",账号id:"+qwUser.getQwUserId());
                }


            }

        });


        return  R.ok();
    }

    private List<QwSopLogs> processInsertSopUserLogsInfo(List<SopUserLogsInfo> sopUserLogsInfos,QwUser qwUser,
                                                         SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                         CourseConfig config,QwCompany qwCompany,int finalSort,int finalSendType,
                                                         Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,List<Company> companies ){

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String companyUserId = String.valueOf(qwUser.getCompanyUserId()).trim();
        String companyId = String.valueOf(qwUser.getCompanyId()).trim();

        Date dataTime;
        if (!StringUtil.strIsNullOrEmpty(param.getSendTime())){
            dataTime = processDate(param.getSendTime());
        }else {
            dataTime=new Date();
        }
        List<QwSopLogs> sopLogsList=new ArrayList<>();

        //域名
//        String domainName = companyUserMapper.selectDomainByUserId(qwUser.getCompanyUserId());
//        if (StringUtils.isEmpty(domainName)){
//            domainName = config.getRealLinkDomainName();
//        }

        String finalDomainName = "domainName";

        sopUserLogsInfos.forEach(item->{

            QwSopLogs sopLogs=new QwSopLogs();

            sopLogs.setQwUserid(item.getQwUserId());
            sopLogs.setExternalUserId(item.getExternalContactId());
            sopLogs.setExternalId(item.getExternalId());
            sopLogs.setLogType(2);
            sopLogs.setSendStatus(3L);
            sopLogs.setSendTime(sdf.format(dataTime));
            sopLogs.setCompanyId(Long.valueOf(companyId));
            sopLogs.setReceivingStatus(0L);
            sopLogs.setSopId(item.getSopId());
            sopLogs.setCorpId(item.getCorpId());
            sopLogs.setFsUserId(item.getFsUserId());

            sopLogs.setSort(finalSort);
            sopLogs.setSendType(finalSendType);

            sopLogs.setExternalUserName(item.getExternalUserName());

            QwExternalContact contact = qwExternalContactMapper.selectQwExternalContactByIdForStageStatus(item.getExternalId());

            QwSopCourseFinishTempSetting setting=new   QwSopCourseFinishTempSetting();

            //草稿
            List<QwSopCourseFinishTempSetting.Setting> draftList=new ArrayList<>();
            QwSopCourseFinishTempSetting.Setting draftSetting=new QwSopCourseFinishTempSetting.Setting();

            switch (finalSendType){
                case 5:
                    List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,
                            contact,dataTime, finalDomainName,miniMap,companies);
                    setting.setSetting(list);
                    break;
                case 9:


                    draftSetting.setContentType("10");
                    draftSetting.setValue("");
                    draftList.add(draftSetting);

                    setting.setSetting(draftList);
                    break;
                case 10:

                    draftSetting.setContentType("11");
                    draftSetting.setValue("");
                    draftList.add(draftSetting);

                    setting.setSetting(draftList);
                    break;
            }


            setting.setType(2);
            setting.setVideoId(param.getVideoId());
            setting.setCourseId(param.getCourseId());
            setting.setCourseType(param.getCourseType());
            try {
                sopLogs.setQwUserKey(qwUser.getId());
            }catch (Exception e){
                log.error("设置qwUserId异常", e);
            }
            sopLogs.setContentJson(JSON.toJSONString(setting));

            sopLogsList.add(sopLogs);
        });



        return sopLogsList;

    }

    private Date processDate(String sendTimeParam){
        // 1. 获取当前日期（年月日）
        LocalDate currentDate = LocalDate.now();

        // 2. 解析传入的时分（支持 "HH:mm" 或 "H:mm"）
        LocalTime sendTime = LocalTime.parse(sendTimeParam);

        // 3. 合并为 LocalDateTime
        LocalDateTime dateTime = LocalDateTime.of(currentDate, sendTime);

        // 4. 转换为 Date（需通过 Instant 和系统默认时区）
        Date date = Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());

        return date;
    }

    private List<QwSopCourseFinishTempSetting.Setting> processSetting(SopUserLogsInfo item, QwUser qwUser,
                                                                      SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                                      CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
                                                                      QwExternalContact contact,Date dataTime,String domainName,
                                                                      Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
                                                                      List<Company> companies ){
        List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);

        for (QwSopCourseFinishTempSetting.Setting st : list) {

            //过滤违禁词
            if ("1".equals(st.getContentType())){
                replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
            }
            //过滤违禁词
            if ("3".equals(st.getContentType())){
                replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
                replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
            }

            switch (st.getContentType()){
                //文字和短链一起
                case "1":
                case "3":
//                    if ("1".equals(st.getIsBindUrl())) {
//
//                        addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), String.valueOf(qwUser.getId()), companyUserId,
//                                companyId, item.getExternalId(),param.getStartTime(),dataTime );
//
//                        String sortLink = generateShortLink(st, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
//                                qwUser.getId(), companyUserId, companyId, domainName,item.getExternalId(),config);
//
//                        if (StringUtils.isNotEmpty(sortLink)) {
//                            if ("3".equals(st.getContentType())) {
//                                st.setLinkUrl(sortLink);
//                            } else {
//                                String currentValue = st.getValue();
//                                if (currentValue == null) {
//                                    st.setValue(sortLink);
//                                } else {
//                                    st.setValue(currentValue
//                                            .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
//                                            .replaceAll("#客户称呼#",StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(contact.getStageStatus())?"同学":contact.getStageStatus())
//                                            + "\n" + sortLink);
//                                }
//                            }
//                        } else {
//                            log.warn("生成短链失败，跳过设置 URL。");
//                        }
//                    }else {
                        if ("1".equals(st.getContentType())) {
                            String defaultName = "同学";
                            if(contact != null && StringUtils.isNotEmpty(contact.getName()) && !"待同步客户".equals(contact.getName())){
                                defaultName = contact.getName();
                            }
                            st.setValue(st.getValue()
                                    .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
                                    .replaceAll("#客户称呼#",contact == null || StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus())?defaultName:contact.getStageStatus()));
                        }
//                    }

                    break;
                //小程序单独
                case "4":

                    addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), String.valueOf(qwUser.getId()), companyUserId, companyId,
                            item.getExternalId(),item.getStartTime(),dataTime );

                    String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), dataTime, param.getCourseId(), param.getVideoId(),
                            qwUser.getId(), companyUserId, companyId, item.getExternalId(), config, null);


                    String miniAppId = null;

                    int effectiveGrade = (item.getGrade() == null) ? 5 : item.getGrade();
                    int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
                    if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
                        Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
                        if (integerListMap != null) {
                            List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);

                            if (miniapps != null && !miniapps.isEmpty()) {
                                CompanyMiniapp companyMiniapp = miniapps.get(0);
                                if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
                                    miniAppId = companyMiniapp.getAppId();
                                }
                            }
                        }
                    }

                    if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
                        miniAppId = qwCompany.getMiniAppId();
                    }
                    st.setMiniType(listIndex);
                    if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
                        st.setMiniprogramAppid(miniAppId);
                    } else {
                        log.error("企业未配置小程序" +  param.getCorpId());
                    }


                    st.setMiniprogramPage(linkByMiniApp);
                    break;
                case "7":
                    QwSop qwSop = qwSopMapper.selectQwSopById(param.getSopId());
                    createVoiceUrl(st, companyUserId, qwSop);
                    break;

                //自定义小程序
                case "10":

                    addWatchLogIfNeeded(item.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), String.valueOf(qwUser.getId()), companyUserId, companyId,
                            item.getExternalId(),item.getStartTime(),dataTime );

                    Optional<Company> matchedCompany = companies.stream()
                            .filter(company -> String.valueOf(company.getCompanyId()).equals(companyId))
                            .findFirst();
                    if (matchedCompany.isPresent()) {
                        Company company = matchedCompany.get();

                        String customMiniAppId = company.getCustomMiniAppId();

                        if (customMiniAppId != null && !customMiniAppId.trim().isEmpty()) {
                            st.setMiniprogramAppid(customMiniAppId);
                        } else {
                            st.setMiniprogramAppid("该公司未配置自定义小程序:"+companyId);
                        }
                    } else {
                        st.setMiniprogramAppid("未找到匹配的公司的自定义小程序:"+companyId);
                    }

                    break;
                //直播小程序单独
                case "12":
                    String sortLiveLink;
                    sortLiveLink = "/pages_course/living?companyId=" + companyId + "&companyUserId=" + companyUserId + "&liveId=" + st.getLiveId();


                    String miniprogramLiveTitle = st.getMiniprogramTitle();
                    int maxLiveLength = 17;
                    st.setMiniprogramTitle(miniprogramLiveTitle.length() > maxLiveLength ? miniprogramLiveTitle.substring(0, maxLiveLength) + "..." : miniprogramLiveTitle);
                    String json = configService.selectConfigByKey("his.config");
                    FSSysConfig sysConfig= JSON.parseObject(json,FSSysConfig.class);
                    st.setMiniprogramAppid(sysConfig.getAppId());
                    st.setMiniprogramPage(sortLiveLink);
                    st.setContentType("4");
                    try {
                        st.setMiniprogramPicUrl(StringUtil.strIsNullOrEmpty(st.getMiniprogramPicUrl()) ? "https://cos.his.cdwjyyh.com/fs/20250331/ec2b4e73be8048afbd526124a655ad56.png" : st.getMiniprogramPicUrl());
                    } catch (Exception e) {
                        log.error("赋值-小程序封面地址失败-" + e);
                    }

                    break;
                default:
                    break;

            }
        }

        return  list;
    }

    private List<QwSopCourseFinishTempSetting.Setting> parseSettings(String jsonData) {
        try {
            if (jsonData.startsWith("[") && jsonData.endsWith("]")) {
                return JSONArray.parseArray(jsonData, QwSopCourseFinishTempSetting.Setting.class);
            } else {
                String fixedJson = JSON.parseObject(jsonData, String.class);
                return JSONArray.parseArray(fixedJson, QwSopCourseFinishTempSetting.Setting.class);
            }
        } catch (Exception e) {
            log.error("解析模板设置失败", e);
            return null;
        }
    }
    // 提取通用替换逻辑的方法
    public void replaceContent(String contentType, String content, Consumer<String> setter, List<FastGptChatReplaceWords> words) {
        if (contentType != null && content != null && !content.isEmpty()) {
            for (FastGptChatReplaceWords word : words) {
                if (content.contains(word.getContent())) {
                    // 如果包含目标字段，则替换
                    setter.accept(content.replace(word.getContent(), word.getChangeCount()));
                }
            }
        }
    }

    private void processAndInsertQwSopLogsBySendMsg(List<QwSopLogs> sopLogsList ) {
        // 定义批量插入的大小
        int batchSize = 500;

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

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

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

    //插入观看记录
    private void addWatchLogIfNeeded(String sopId, Integer videoId, Integer courseId,
                                     Long fsUserId, String qwUserId, String companyUserId,
                                     String companyId, Long externalId, String startTime,Date createTime) {

        try {
            FsCourseWatchLog watchLog = new FsCourseWatchLog();
            watchLog.setVideoId(videoId != null ? videoId.longValue() : null);
            watchLog.setQwExternalContactId(externalId);
            watchLog.setSendType(2);
            watchLog.setQwUserId(Long.valueOf(qwUserId));
            watchLog.setSopId(sopId);
            watchLog.setDuration(0L);
            watchLog.setCourseId(courseId != null ? courseId.longValue() : null);
            watchLog.setCompanyUserId(companyUserId != null ? Long.valueOf(companyUserId) : null);
            watchLog.setCompanyId(companyId != null ? Long.valueOf(companyId) : null);
            watchLog.setCreateTime(createTime);
            watchLog.setUpdateTime(createTime);
            watchLog.setLogType(3);
            watchLog.setUserId(fsUserId);
            watchLog.setCampPeriodTime(convertStringToDate(startTime,"yyyy-MM-dd"));

            //存看课记录
            fsCourseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
        }catch (Exception e){
            log.error("一键群发失败-插入观看记录失败："+e.getMessage());
        }


    }

    private String generateShortLink(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
                                     Integer courseId, Integer videoId, Long qwUserId,
                                     String companyUserId, String companyId,String domainName, Long externalId,CourseConfig config) {

        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
                companyUserId, companyId, externalId,0,null);

        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);

        String courseJson = JSON.toJSONString(courseMap);
        String realLinkFull = REAL_LINK_PREFIX + courseJson;
        link.setRealLink(realLinkFull);

        Date updateTime = createUpdateTime(setting, sendTime, config);

        link.setUpdateTime(updateTime);

        String sortLink = createLink(link,domainName);

        //存短链-
        fsCourseLinkMapper.insertFsCourseLink(link);

        return sortLink.replaceAll("^[\\s\\u2005]+", "");
    }

    private String createLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
                                     Integer courseId, Integer videoId, Long qwUserId,
                                     String companyUserId, String companyId, Long externalId,CourseConfig config, String chatId) {

        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
                                                companyUserId, companyId, externalId,3,chatId);

        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);

        String courseJson = JSON.toJSONString(courseMap);
        String realLinkFull = miniappRealLink + courseJson;
        link.setRealLink(realLinkFull);

        Date updateTime = createUpdateTime(setting, sendTime, config);

        link.setUpdateTime(updateTime);
        //存短链-
        fsCourseLinkMapper.insertFsCourseLink(link);
        return link.getRealLink().replaceAll("^[\\s\\u2005]+", "");
    }

    private QwCreateLinkByAppVO createLinkByApp(QwSopCourseFinishTempSetting.Setting setting, String corpId,
                                                Date sendTime, Integer courseId, Integer videoId, Long qwUserId,
                                                String companyUserId, String companyId, Long externalId,
                                                CourseConfig config,String qwUserName,Long fsUserId){

        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
                companyUserId, companyId, externalId,4,null);

        FsCourseRealLink courseMap = new FsCourseRealLink();
        BeanUtils.copyProperties(link,courseMap);

        String courseJson = JSON.toJSONString(courseMap);
        String realLinkFull = REAL_LINK_PREFIX + courseJson;
        link.setRealLink(realLinkFull);

        Date updateTime = createUpdateTime(setting, sendTime, config);

        link.setUpdateTime(updateTime);

        String sortLink = appLink+link.getLink()+"&videoId="+videoId;

        String appMsgLink=appRealLink+link.getLink();

        QwCreateLinkByAppVO byAppVO=new QwCreateLinkByAppVO();
        byAppVO.setSortLink(sortLink);
        byAppVO.setAppMsgLink(appMsgLink);

            //异步生成app链接记录
        asyncSopTestService.createFsCourseSopAppLink(link.getLink(),sendTime,updateTime,companyId,companyUserId,String.valueOf(qwUserId),
                qwUserName,corpId,courseId,setting.getLinkTitle(),setting.getLinkImageUrl(),videoId,
                setting.getLinkDescribe(),appMsgLink,externalId);

        //异步给app用户发送消息
        asyncSopTestService.asyncSendMsgBySopAppLink(externalId,setting.getLinkTitle(),setting.getLinkDescribe(),appMsgLink);



        //存短链-
        fsCourseLinkMapper.insertFsCourseLink(link);

        return byAppVO;
    }



    private String createLink(FsCourseLink link,String domain){
        String sortLink = domain + SHORT_LINK_PREFIX + link.getLink();
        return sortLink;
    }

    private Date createUpdateTime(QwSopCourseFinishTempSetting.Setting setting,Date sendTime,CourseConfig config){

        Integer expireDays = (setting.getExpiresDays() == null || setting.getExpiresDays() == 0)
                ? config.getVideoLinkExpireDate()
                : setting.getExpiresDays();

//         使用 Java 8 时间 API 计算过期时间
        LocalDateTime sendDateTime = sendTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime expireDateTime = sendDateTime.plusDays(expireDays-1);
        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());

        return updateTime;
    }

    public FsCourseLink createFsCourseLink(String corpId, Date sendTime, Integer courseId, Integer videoId, Long qwUserId,
                                           String companyUserId, String companyId, Long externalId, Integer type, String chatId) {
        // 手动创建 FsCourseLink 对象，避免使用 BeanUtils.copyProperties
        FsCourseLink link = new FsCourseLink();
        link.setCompanyId(Long.parseLong(companyId));
        link.setQwUserId(qwUserId);
        link.setCompanyUserId(Long.parseLong(companyUserId));
        link.setVideoId(videoId.longValue());
        link.setCorpId(corpId);
        link.setCourseId(courseId.longValue());
        link.setChatId(chatId);
        link.setQwExternalId(externalId);
        link.setLinkType(type); //小程序
        link.setUNo(UUID.randomUUID().toString());
        String randomString = generateRandomStringWithLock();
        if (StringUtil.strIsNullOrEmpty(randomString)) {
            link.setLink(UUID.randomUUID().toString().replace("-", ""));
        } else {
            link.setLink(randomString);
        }

        link.setCreateTime(sendTime);
        link.setProjectCode(cloudHostProper.getProjectCode());

        return link;
    }

    /**
     * 时间字符串转Date时间
     * @param dateString
     * @return
     */
    public static Date convertStringToDate(String dateString,String pattern) {
        if (dateString == null || dateString.isEmpty()) {
            return null;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime localDateTime;
        LocalDate localDate;
        // 先解析成 LocalDate（只含年月日）
        if (pattern.equals("yyyy-MM-dd")){
            // 先解析成 LocalDate（只含年月日）
            localDate = LocalDate.parse(dateString, formatter);
            // 将 LocalDate 转为当天 00:00:00 的 LocalDateTime
            localDateTime = localDate.atStartOfDay();
        }else {
            localDateTime = LocalDateTime.parse(dateString, formatter);
        }
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }


}
