package com.fs.course.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fs.common.BeanCopyUtils;
import com.fs.common.core.domain.R;
import com.fs.common.core.domain.ResponseResult;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.enums.BizResponseEnum;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.common.utils.date.DateUtil;
import com.fs.company.domain.CompanyUser;
import com.fs.company.mapper.CompanyUserMapper;
import com.fs.course.config.CourseConfig;
import com.fs.course.domain.*;
import com.fs.course.dto.CoursePackageDTO;
import com.fs.course.mapper.*;
import com.fs.course.param.*;
import com.fs.course.param.newfs.*;
import com.fs.course.service.IFsUserCourseVideoService;
import com.fs.course.service.IFsVideoResourceService;
import com.fs.course.vo.FsCourseVideoListBySidebarVO;
import com.fs.course.vo.FsUserCourseVideoListUVO;
import com.fs.course.vo.FsUserCourseVideoQVO;
import com.fs.course.vo.FsUserCourseVideoVO;
import com.fs.course.vo.newfs.*;
import com.fs.his.param.WxSendRedPacketParam;
import com.fs.his.vo.OptionsVO;
import com.fs.qw.domain.QwCompany;
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.service.IQwCompanyService;
import com.fs.qwApi.Result.QwAddContactWayResult;
import com.fs.qwApi.param.QwAddContactWayParam;
import com.fs.qwApi.service.QwApiService;
import com.fs.sop.mapper.QwSopLogsMapper;
import com.fs.sop.mapper.SopUserLogsInfoMapper;
import com.fs.sop.service.ISopUserLogsInfoService;
import com.fs.store.domain.FsUser;
import com.fs.store.domain.FsUserCompanyUser;
import com.fs.store.domain.FsUserIntegralLogs;
import com.fs.store.mapper.FsUserCompanyUserMapper;
import com.fs.store.mapper.FsUserIntegralLogsMapper;
import com.fs.store.mapper.FsUserMapper;
import com.fs.store.service.IFsStorePaymentService;
import com.fs.store.service.IFsUserService;
import com.fs.store.service.cache.IFsUserCourseCacheService;
import com.fs.system.service.ISysConfigService;
import com.fs.voice.utils.StringUtil;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
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 org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

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

/**
 * 课堂视频Service业务层处理
 *
 * @author fs
 * @date 2024-05-17
 */
@Slf4j
@Service
public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
{
    private static final Logger logger = LoggerFactory.getLogger(FsUserCourseVideoServiceImpl.class);

    private static final String miniappRealLink = "/pages_course/video.html?course=";
    private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
    private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";

    @Autowired
    private FsUserCourseVideoMapper fsUserCourseVideoMapper;
    @Autowired
    private IFsUserService fsUserService;
    @Autowired
    private FsUserCourseStudyLogMapper courseStudyLogMapper;

    @Autowired
    private FsUserCourseOrderMapper fsUserCourseOrderMapper;

    @Autowired
    private FsCourseQuestionBankMapper courseQuestionBankMapper;
    @Autowired
    private FsCourseWatchLogMapper courseWatchLogMapper;


    @Autowired
    private ISopUserLogsInfoService iSopUserLogsInfoService;

    @Autowired
    private QwExternalContactMapper qwExternalContactMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private FsCourseSopLogsMapper courseSopLogsMapper;
    @Autowired
    private QwApiService qwApiService;
//    @Autowired
//    private IAdHtmlClickLogService adHtmlClickLogService;
    @Autowired
    private QwUserMapper qwUserMapper;
    @Autowired
    private FsUserCourseVideoRedPackageMapper fsUserCourseVideoRedPackageMapper;
    @Autowired
    private FsCourseTrafficLogMapper fsCourseTrafficLogMapper;
    @Autowired
    private FsUserIntegralLogsMapper fsUserIntegralLogsMapper;
    @Autowired
    private FsUserMapper fsUserMapper;
    @Autowired
    private IFsStorePaymentService paymentService;
    @Autowired
    private FsCourseRedPacketLogMapper redPacketLogMapper;
    @Autowired
    private FsCourseFinishTempMapper fsCourseFinishTempMapper;

    @Autowired
    private QwSopLogsMapper qwSopLogsMapper;
    @Autowired
    private FsCourseLinkMapper courseLinkMapper;
    @Autowired
    RedisCache redisCache;
    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private CompanyUserMapper companyUserMapper;

    @Autowired
    private IFsVideoResourceService fsVideoResourceService;
    @Autowired
    private FsVideoResourceMapper fsVideoResourceMapper;

    @Autowired
    private FsUserCourseMapper fsUserCourseMapper;

    @Autowired
    private FsUserCoursePeriodMapper fsUserCoursePeriodMapper;

    @Autowired
    private FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;

    @Autowired
    private FsUserCompanyUserMapper fsUserCompanyUserMapper;
    @Autowired
    private IFsUserCourseCacheService fsUserCourseCacheService;
    @Autowired
    private IQwCompanyService qwCompanyService;
    @Autowired
    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
    @Autowired
    private FsCourseLinkMapper fsCourseLinkMapper;

    @Autowired
    private FsUserCourseCompanyUserTimeMapper companyUserTimeMapper;
    /**
     * 查询课堂视频
     *
     * @param videoId 课堂视频主键
     * @return 课堂视频
     */
    @Override
    public FsUserCourseVideo selectFsUserCourseVideoByVideoId(Long videoId)
    {
        return fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
    }

    @Override
    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId) {
        FsUserCourseVideoQVO fsUserCourseVideoQVO=new FsUserCourseVideoQVO();
        FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);

        BeanCopyUtils.copy(courseVideo,fsUserCourseVideoQVO);

        if (StringUtils.isNotEmpty(courseVideo.getQuestionBankId())){
            List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(courseVideo.getQuestionBankId().split(","));
            fsUserCourseVideoQVO.setQuestionBankList(fsCourseQuestionBanks);
        }
        return fsUserCourseVideoQVO;
    }

    /**
     * 查询课堂视频列表
     *
     * @param fsUserCourseVideo 课堂视频
     * @return 课堂视频
     */
    @Override
    public List<FsUserCourseVideo> selectFsUserCourseVideoList(FsUserCourseVideo fsUserCourseVideo)
    {
        return fsUserCourseVideoMapper.selectFsUserCourseVideoList(fsUserCourseVideo);
    }

    /**
     * 新增课堂视频
     *
     * @param fsUserCourseVideo 课堂视频
     * @return 结果
     */
    @Override
    public int insertFsUserCourseVideo(FsUserCourseVideo fsUserCourseVideo)
    {
        fsUserCourseVideo.setCreateTime(DateUtils.getNowDate());
        return fsUserCourseVideoMapper.insertFsUserCourseVideo(fsUserCourseVideo);
    }

    /**
     * 修改课堂视频
     *
     * @param fsUserCourseVideo 课堂视频
     * @return 结果
     */
    @Override
    public int updateFsUserCourseVideo(FsUserCourseVideo fsUserCourseVideo)
    {
        fsUserCourseVideo.setUpdateTime(DateUtils.getNowDate());
        return fsUserCourseVideoMapper.updateFsUserCourseVideo(fsUserCourseVideo);
    }

    /**
     * 批量删除课堂视频
     *
     * @param videoIds 需要删除的课堂视频主键
     * @return 结果
     */
    @Override
    public int deleteFsUserCourseVideoByVideoIds(String[] videoIds)
    {
        return fsUserCourseVideoMapper.deleteFsUserCourseVideoByVideoIds(videoIds);
    }

    /**
     * 删除课堂视频信息
     *
     * @param videoId 课堂视频主键
     * @return 结果
     */
    @Override
    public int deleteFsUserCourseVideoByVideoId(String videoId)
    {
        return fsUserCourseVideoMapper.deleteFsUserCourseVideoByVideoId(videoId);
    }

    @Override
    public List<FsUserCourseVideo> selectFsUserCourseVideoListByCourseId(FsUserCourseVideo fsUserCourseVideo) {
        return fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseId(fsUserCourseVideo);
    }

    @Override
    public List<FsUserCourseVideoListUVO> selectFsUserCourseVideoListUVOByCourseId(FsUserCourseVideoListUParam param) {
        List<FsUserCourseVideoListUVO> list;
        if (param == null || param.getUserId() == null) {
            list = fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseIdAll(param);

            // 判断是否对前两条记录设置 isVip
            if (!list.isEmpty()) {
                list.stream()
                        .filter(video -> video.getCourseSort() == 1 || video.getCourseSort() == 2)
                        .forEach(video -> video.setIsVip(0));
            }
        } else {
            list = fsUserCourseVideoMapper.selectFsUserCourseVideoListUVOByCourseId(param);
            FsUserCourseOrder order = fsUserCourseOrderMapper.selectFsUserCourseOrderByCourse(param.getUserId(),param.getCourseId());
            if (order!=null&&order.getCreateType()==1){
                list.forEach(item -> item.setIsBuy(1));
            }
            for (FsUserCourseVideoListUVO videoListUVO : list) {
                FsUserCourseStudyLog studyLog = courseStudyLogMapper.selectFsUserCourseStudyLogByUser(param.getUserId(), videoListUVO.getVideoId());
                if (studyLog != null) {
                    videoListUVO.setStudyTime(studyLog.getCurrentTimes());
                    videoListUVO.setTotalTimes(studyLog.getTotalTimes());
                }
            }
            if (!list.isEmpty()) {
                list.stream()
                        .filter(video -> video.getCourseSort() == 1 || video.getCourseSort() == 2)
                        .forEach(video -> {
                            video.setIsVip(0);
                            video.setIsBuy(1);
                        });
            }

        }
        for (FsUserCourseVideoListUVO listUVO : list){
            if (StringUtils.isNotEmpty(listUVO.getPackageJson())){
                List<CoursePackageDTO> packageDTOS = JSON.parseArray(listUVO.getPackageJson(),CoursePackageDTO.class);
                for (CoursePackageDTO packageDTO : packageDTOS){
                    // 将时间按 ":" 分割
                    String[] parts = packageDTO.getDuration().split(":");
                    // 提取小时和分钟
                    int hours = Integer.parseInt(parts[0]);
                    int minutes = Integer.parseInt(parts[1]);
                    // 转换为秒
                    int seconds = hours * 3600 + minutes * 60;
                    packageDTO.setDuration(String.valueOf(seconds));
                }
                listUVO.setPackageJson(JSON.toJSONString(packageDTOS));
            }

        }
        return list;

    }

    @Override
    public Long selectCourseVideoSort(Long courseId) {
        if (fsUserCourseVideoMapper.selectCourseVideoSort(courseId)!=null){
            Long lastSort =  fsUserCourseVideoMapper.selectCourseVideoSort(courseId)+1;
            return lastSort;
        }
        return 1L;
    }

    @Override
    public R updateWatchDuration(FsUserCourseVideoFinishUParam param) {
        //临时短链不做记录
        if (param.getLinkType()!=null && param.getLinkType()==1){
            return R.ok();
        }

        if (param.getIsRoom()!=null&&param.getIsRoom()==1&&param.getQwExternalId()==null){
            return R.ok();
        }

        // 从Redis中获取观看时长
        String redisKey = "h5user:watch:duration:" + param.getQwUserId()+ ":" + param.getQwExternalId() + ":" + param.getVideoId();
        log.info("看课redis-key：{}", redisKey);
        try {
            String durationStr = redisCache.getCacheObject(redisKey);
            Long duration = durationStr != null ? Long.parseLong(durationStr) : 0L;

            // 更新Redis中的观看时长
            if (param.getDuration() != null && param.getDuration() > duration) {
                //24小时过期
                redisCache.setCacheObject(redisKey, param.getDuration().toString(),2,TimeUnit.HOURS);
            }
            updateHeartbeat(param);
            return R.ok();
        }catch (Exception e){
            e.printStackTrace();
            logger.error("更新时长失败：{}",redisKey,e.getMessage());
            return R.error();
        }

    }

    //更新心跳时间
    public void updateHeartbeat(FsUserCourseVideoFinishUParam param) {
        String redisKey = "h5user:watch:heartbeat:" + param.getQwUserId()+ ":" + param.getQwExternalId() + ":" + param.getVideoId();
        redisCache.setCacheObject(redisKey, LocalDateTime.now().toString());
        // 设置 Redis 记录的过期时间（例如 5 分钟）
        redisCache.expire(redisKey, 300, TimeUnit.SECONDS);
    }

    @Override
    @Transactional
    public R isAddKf(FsUserCourseVideoAddKfUParam param) {
        logger.info("zyp \n【判断添加客服】：{}",param);
        //查询用户
        FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
        //用户不存在唤起重新授权
        if (fsUser==null){
            return R.error(504,"未授权");
        }

        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";

        Integer isRoom = param.getIsRoom();

        // 处理逻辑
        if (isRoom == null || isRoom == 0) {
            // 当 isRoom 为 null 或 0 时走 handleExt
            return handleExt(param,msg);
        } else if (isRoom == 1) {
            // 当 isRoom 为 1 时走 handleRoom
            return handleRoom(param,fsUser);
        } else {
            // 非法参数
            logger.warn("非法参数 isRoom: {}", isRoom);
            return R.error("参数错误！");
        }

    }

    private R handleRoom(FsUserCourseVideoAddKfUParam param,FsUser user) {
        if (user.getQwExtId()==null){
            return R.error("未注册");
        }
        param.setQwExternalId(user.getQwExtId());
        //查询是否有添加客服
        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
        if (externalContact==null){
            return R.error("客户不存在！");
        }
        if (!externalContact.getQwUserId().equals(param.getUserId())){
            return R.error("无权限观看，添加群主非本群主");
        }
        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(param.getQwExternalId(), param.getVideoId(),param.getQwUserId());
        if (log==null){
            createWatchLog(param);
        }
        return R.ok();
    }

    private void createWatchLog(FsUserCourseVideoAddKfUParam param) {
        FsCourseWatchLog log = new FsCourseWatchLog();
        BeanUtils.copyProperties(param,log);
        log.setQwExternalContactId(param.getQwExternalId());
        log.setSendType(2);
        log.setDuration(0L);
        log.setCreateTime(new Date());
        log.setLogType(3);
        courseWatchLogMapper.insertFsCourseWatchLog(log);
    }

    private R handleExt(FsUserCourseVideoAddKfUParam param,String msg){
        if (param.getLinkType()!=null&&param.getLinkType()==1){
            if (param.getLinkId()!=null){
                // 从数据库中查找短链对应的真实链接
                FsCourseLink courseLink = courseLinkMapper.selectFsCourseLinkByLinkId(param.getLinkId());
                if (courseLink != null) {
                    // 获取当前时间
                    Date currentTime = new Date();
                    // 获取链接的更新时间（假设这个字段代表过期时间）
                    Date updateTime = courseLink.getUpdateTime();

                    // 判断是否过期
                    if (currentTime.after(updateTime)) {
                        // 链接已过期
                        return R.error("链接已过期");
                    }else {
                        return R.ok();
                    }
                }
            }
            return R.error("链接过期");
        }



        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(param.getQwExternalId(), param.getVideoId(),param.getQwUserId());
        if (log==null ){
            return addCustomerService(param.getQwUserId(),msg);
        }

        //查询是否有添加客服
        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());

        //用小程序id查询外部联系人
        List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByMiniUserId(param.getUserId());


        //如果查不出来客户信息，加好友
        if(externalContact==null){
            return addCustomerService(param.getQwUserId(),msg);
        }

        //判断外部联系人有没有绑定userId
        if (externalContact.getFsUserId()!=null){
            //有客户有小程序id  但 登录的小程序id和根据外部联系人id查出来的小程序id不一致
            if (!externalContact.getFsUserId().equals(param.getUserId())) {
                return addCustomerService(param.getQwUserId(),msg);
            }
            //匹配客户公司id
            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))){
                return addCustomerService(param.getQwUserId(),msg);
            }

            //看课记录中userId为0绑定userId
            if (log.getUserId()==null||log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())){
                log.setUserId(param.getUserId());
            }
            log.setUpdateTime(new Date());
            courseWatchLogMapper.updateFsCourseWatchLog(log);

            iSopUserLogsInfoService.updateSopUserInfoByExternalId(externalContact.getId(),param.getUserId());

            return R.ok();

        }else {
            //没绑定fsUser直接绑定fsUser
            QwExternalContact contact = new QwExternalContact();
            contact.setId(param.getQwExternalId());
            contact.setFsUserId(param.getUserId());
            qwExternalContactMapper.updateQwExternalContact(contact);
            FsUser user = new FsUser();
            user.setUserId(param.getUserId());
            user.setIsAddQw(1);
            user.setQwExtId(param.getQwExternalId());
            fsUserMapper.updateFsUser(user);

            iSopUserLogsInfoService.updateSopUserInfoByExternalId(externalContact.getId(),param.getUserId());

            //绑定上之后 更新观看记录
            //看课记录中userId为0绑定userId
            if (log.getUserId()==null||log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())){
                log.setUserId(param.getUserId());
            }

            log.setUpdateTime(new Date());
            courseWatchLogMapper.updateFsCourseWatchLog(log);
            return R.ok();
        }
    }

    private R addCustomerService(String qwUserById,String msg){
        String contactWay = "";
        QwUser qwUser = qwUserMapper.selectQwUserById(Long.parseLong(qwUserById));
        if (qwUser==null){
            return R.error("客服不存在");
        }
        if (StringUtils.isNotEmpty(qwUser.getContactWay())){
            contactWay = qwUser.getContactWay();
        }
        else {
            String qwUserId = "[\"" + qwUser.getQwUserId() + "\"]";
            List<String> users = JSON.parseArray(qwUserId, String.class);
            QwAddContactWayParam qwAddContactWayParam = new QwAddContactWayParam();
            qwAddContactWayParam.setType(1);
            qwAddContactWayParam.setScene(2);
            qwAddContactWayParam.setUser(users);
            qwAddContactWayParam.setSkip_verify(true);
            QwAddContactWayResult qwAddContactWayResult = qwApiService.addContactWay(qwAddContactWayParam, qwUser.getCorpId());
            if (qwAddContactWayResult.getErrcode() == 0) {
                qwUser.setContactWay(qwAddContactWayResult.getQr_code());
                qwUser.setConfigId(qwAddContactWayResult.getConfig_id());
                qwUserMapper.updateQwUser(qwUser);
                contactWay = qwUser.getContactWay();
            } else {
                return R.error("请联系管理员>>>"+qwAddContactWayResult.getErrmsg());
            }
        }
        return R.error(400,msg).put("qrcode",contactWay);
    }

    @Override
    public List<FsUserCourseVideoVO> selectFsUserCourseVideoListByCourseIdAndCompany(FsUserCourseVideoParam fsUserCourseVideo) {
        return fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseIdAndCompany(fsUserCourseVideo);
    }

    @Override
    public R updateFsUserCourseVideoCompanyRedPacket(FsUserCourseVideoParam fsUserCourseVideo) {
        fsUserCourseVideoRedPackageMapper.insertOrUpdateFsUserCourseVideoRedPackage(fsUserCourseVideo);
        return R.ok();
    }


    @Transactional
    @Override
    public R getInternetTraffic(FsUserCourseVideoFinishUParam param) {
        try {
            FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
            trafficLog.setQwExternalContactId(param.getQwExternalId());
            trafficLog.setUserId(param.getUserId());
            trafficLog.setCreateTime(new Date());
//            trafficLog.setTime(new Date());
            BeanUtils.copyProperties(param, trafficLog);

            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
            if (video == null) {
                return R.error("视频不存在");
            }

            // 计算流量
            BigDecimal result = param.getBufferRate().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
            BigDecimal longAsBigDecimal = BigDecimal.valueOf(video.getFileSize());
            long roundedResult = result.multiply(longAsBigDecimal).setScale(0, RoundingMode.HALF_UP).longValue();
            trafficLog.setInternetTraffic(roundedResult);

            // 获取课程所属项目id
            FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
            if(fsUserCourse != null){
                trafficLog.setProject(fsUserCourse.getProject());
            }

            // 处理 UUID 为空的情况
            if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                // 直接插入或更新
//                logger.error("zyp \n【插入或更新流量】：{}",trafficLog);
//                if(ObjectUtils.isNotNull(trafficLog.getCourseId())) {
//                    FsUserCourse course = fsUserCourseCacheService.selectFsUserCourseByCourseId(trafficLog.getCourseId());
//                    if(ObjectUtils.isNotNull(course)){
//                        trafficLog.setProject(course.getProject());
//                    }
//                }
                fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("zyp \n【插入或更新流量失败】：{}",e.getMessage());
            return R.error();
        }
        return R.ok();
    }


    @Override
    public R getIntegralByH5Video(FsUserCourseVideoFinishUParam param) {
//        //临时短链不做处理
//        if (param.getLinkType()!=null&&param.getLinkType()==1){
//            return R.ok();
//        }
//        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(),param.getVideoId(),param.getQwUserId(), param.getQwExternalId());
//        if (log==null){
//            return R.error("无记录");
//        }
//        if (log.getLogType()==2){
//            return R.error("已存在完课记录");
//        }
//        if (log.getLogType()==1){
//            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
//            if (video==null){
//                return R.error("课程视频不存在！");
//            }
//            FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
//            if (user!=null){
//                //判断该视频可增加积分的此时 （每十分钟增加积分）
//                Long count = video.getDuration()/600;
//                Long getIntegralCount = fsUserIntegralLogsMapper.selectH5VideoIntegralCount(param.getUserId(), param.getVideoId());
//                if (getIntegralCount.equals(count)){
//                    return R.error("该课堂或积分已达限制！");
//                }
//                String json = configService.selectConfigByKey("course.config");
//                CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
//                //增加积分
//                FsUser userMap=new FsUser();
//                userMap.setUserId(user.getUserId());
//                userMap.setIntegral(user.getIntegral()+config.getVideoIntegral());
//                fsUserMapper.updateFsUser(userMap);
//                FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
//                integralLogs.setIntegral(config.getVideoIntegral().longValue());
//                integralLogs.setUserId(user.getUserId());
//                integralLogs.setBalance(userMap.getIntegral());
//                integralLogs.setLogType(16);
//                integralLogs.setBusinessId(log.getLogId().toString());
//                integralLogs.setCreateTime(new Date());
//                fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
//
//                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
//                redPacketLog.setCourseId(log.getCourseId());
//                redPacketLog.setOutBatchNo(integralLogs.getId().toString());
//                redPacketLog.setCompanyId(log.getCompanyId());
//                redPacketLog.setUserId(log.getUserId());
//                redPacketLog.setVideoId(log.getVideoId());
//                redPacketLog.setStatus(1);
//                redPacketLog.setQwUserId(log.getQwUserId() != null ? log.getQwUserId() : null );
//                redPacketLog.setCompanyUserId(log.getCompanyUserId());
//                redPacketLog.setCreateTime(new Date());
//                redPacketLog.setAmount(BigDecimal.valueOf(config.getVideoIntegral()).divide(BigDecimal.valueOf(1000)));
//                redPacketLog.setRemark("点播看课获得积分转");
//                redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
//                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
//                return R.ok();
//            }
//        }
        return R.error();
    }


    @Override
    @Transactional
    public R sendReward(FsCourseSendRewardUParam param) {
        // 获取用户信息
        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
//        if (StringUtils.isEmpty(user.getMpOpenId())){
//            return R.error("未识别到领取信息");
//        }
        FsCourseWatchLog log = new FsCourseWatchLog();

        // 根据链接类型判断是否已发放奖励
        if (param.getLinkType() != null && param.getLinkType() == 1) {
            FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(), param.getUserId());
            if (packetLog != null) {
                return R.error("奖励已发放");
            }
        } else {
            log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
            if (log == null) {
                return R.error("无记录");
            }
            if (log.getRewardType() != null) {
                return R.error("奖励已发放");
            }
        }

        // 获取视频信息
        FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());

        // 获取配置信息
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        // 根据奖励类型发放不同奖励
        switch (config.getRewardType()) {
            // 红包奖励
            case 1:
                return sendRedPacketReward(param, user, log, video, config);
            // 积分奖励
            case 2:
                return sendIntegralReward(user, log, config);
            default:
                return R.error("参数错误！");
        }
    }

    @Override
    public R sendRewardByFsUser(FsCourseSendRewardUParam param) {
        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
        if (user == null){
            return R.error("未识别到用户信息");
        }
        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByFsUser(param.getUserId(), param.getVideoId(), param.getCompanyUserId());
        if (log == null) {
            return R.error("无记录");
        }
        if (log.getRewardType() != null) {
            return R.error("奖励已发放");
        }


        // 获取视频信息
        FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());

        // 获取配置信息
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        // 根据奖励类型发放不同奖励
        switch (config.getRewardType()) {
            // 红包奖励
            case 1:
                return sendRedPacketReward(param, user, log, video, config);
            // 积分奖励
            case 2:
                return sendIntegralReward(user, log, config);
            default:
                return R.error("参数错误！");
        }
    }

    /**
     * 发放红包奖励
     *
     * @param param 请求参数
     * @param user 用户信息
     * @param log 观看日志
     * @param video 视频信息
     * @param config 配置信息
     * @return 处理结果
     */
    private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
        // 判断是否属于领取红包时间（会员看课发放红包）
        FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
        periodDays.setVideoId(param.getVideoId());
        periodDays.setPeriodId(param.getPeriodId());
        //正常情况是只能查询到一条，之前可能存在重复的脏数据，暂使用查询list的方式
        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
        if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
            periodDays = fsUserCoursePeriodDays.get(0);
        }

        if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
            return R.error(403,"已超过领取红包时间");
        }

        // 确定红包金额
        BigDecimal amount = BigDecimal.ZERO;
        FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId(), param.getPeriodId());

        if (redPackage != null) {
            amount = redPackage.getRedPacketMoney();
        } else if (video != null) {
            amount = video.getRedPacketMoney();
        }

        // 准备发送红包参数
        WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
        packetParam.setOpenId(user.getMpOpenId());
        // 来源是小程序切换openId
        if (param.getSource() == 2) {
            packetParam.setOpenId(user.getMaOpenId());
        }
        packetParam.setAmount(amount);
        packetParam.setSource(param.getSource());
        packetParam.setRedPacketMode(config.getRedPacketMode());
        packetParam.setCompanyId(param.getCompanyId());


        // 发送红包
        R sendRedPacket = paymentService.sendRedPacket(packetParam);
        if (sendRedPacket.get("code").equals(200)) {
            FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
            TransferBillsResult transferBillsResult;
            if (sendRedPacket.get("isNew").equals(1)){
                transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
                redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
            }else {
                redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
            }
            // 添加红包记录
            redPacketLog.setCourseId(param.getCourseId());
//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
            redPacketLog.setCompanyId(param.getCompanyId());
            redPacketLog.setUserId(param.getUserId());
            redPacketLog.setVideoId(param.getVideoId());
            redPacketLog.setStatus(0);
            redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
            redPacketLog.setCompanyUserId(param.getCompanyUserId());
            redPacketLog.setCreateTime(new Date());
            redPacketLog.setAmount(amount);
            redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
            redPacketLog.setPeriodId(param.getPeriodId());
            redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);

            // 更新观看记录的奖励类型
//            if (param.getLinkType() == null || param.getLinkType() == 0) {
            log.setRewardType(config.getRewardType());
            courseWatchLogMapper.updateFsCourseWatchLog(log);
//            }
            return sendRedPacket;
        } else {
            return R.error("奖励发送失败，请联系客服");
        }
    }

    /**
     * 发放积分奖励
     *
     * @param user 用户信息
     * @param log 观看日志
     * @param config 配置信息
     * @return 处理结果
     */
    private R sendIntegralReward(FsUser user, FsCourseWatchLog log, CourseConfig config) {
        // 更新用户积分
        FsUser userMap = new FsUser();
        userMap.setUserId(user.getUserId());
        userMap.setIntegral(NumberUtil.add(user.getIntegral(), config.getAnswerIntegral()));
        fsUserMapper.updateFsUser(userMap);

        // 记录积分日志
        FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
        integralLogs.setIntegral(new BigDecimal(config.getAnswerIntegral()));
        integralLogs.setUserId(user.getUserId());
        integralLogs.setBalance(userMap.getIntegral());
        integralLogs.setLogType(17);
        integralLogs.setBusinessId(StringUtils.isNotEmpty(log.getLogId().toString()) ? log.getLogId().toString() : null);
        integralLogs.setCreateTime(new Date());
        fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);

        //更新看课记录的奖励类型
        log.setRewardType(config.getRewardType());
        courseWatchLogMapper.updateFsCourseWatchLog(log);
        logger.info("发放奖励====================》看课记录,{}",log);

        return R.ok("奖励发放成功");
    }

    @Override
    public List<FsUserCourseVideoPageListVO> pageListCourseVideo(UserCourseVideoPageParam param) {
        return fsUserCourseVideoMapper.selectFsUserCourseVideoPageList(param);
    }

    @Override
    public ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId) {
        FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
        FsUserCourseVideoDetailsVO fsUserCourseVideoDetailsVO = new FsUserCourseVideoDetailsVO();
        BeanUtils.copyProperties(fsUserCourseVideo, fsUserCourseVideoDetailsVO);

        // 获取课程相关的题库
        String questionBankId = fsUserCourseVideo.getQuestionBankId();
        List<FsUserVideoQuestionVO> questionList = Collections.emptyList();
        if (StringUtils.isNotEmpty(questionBankId)) {
            String[] questionBankIds = questionBankId.split(",");
            List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(questionBankIds);
            questionList = fsCourseQuestionBanks.stream().map(v -> {
                FsUserVideoQuestionVO fsUserVideoQuestionVO = new FsUserVideoQuestionVO();
                BeanUtils.copyProperties(v, fsUserVideoQuestionVO);
                return fsUserVideoQuestionVO;
            }).collect(Collectors.toList());
        }

        fsUserCourseVideoDetailsVO.setQuestionBankList(questionList);
        return ResponseResult.ok(fsUserCourseVideoDetailsVO);
    }

    @Autowired
    SopUserLogsInfoMapper sopUserLogsInfoMapper;

    @Override
    public R registerCourse(FsUserCourseRegisterParam param) {


        FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
        if (fsUser==null){
            return R.error("未登录成功");
        }
        logger.info(""+fsUser);
        if (fsUser.getIsAddQw()==1){
            return R.error("已经注册");
        }
        QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
        if (qwExternalContact==null){
            return R.error("注册信息错误");
        }
        FsUser u = new FsUser();
        u.setUserId(param.getUserId());
        u.setIsAddQw(1);
        u.setQwExtId(param.getQwExternalId());
        fsUserMapper.updateFsUser(u);
        QwExternalContact qw = new QwExternalContact();
        qw.setFsUserId(fsUser.getUserId());
        qw.setId(qwExternalContact.getId());
        qwExternalContactMapper.updateById(qw);
        List<String> list= sopUserLogsInfoMapper.selectSopUserLogsInfoByExtId(qwExternalContact.getId());
        if (list!=null&& !list.isEmpty()){
            sopUserLogsInfoMapper.updateSopUserLogsInfoFsUserIdById(list,param.getUserId());
        }
        return R.ok();
    }

    @Override
    public List<FsUserVideoListVO> getListCourseVideo(UserCourseVideoPageParam param) {
        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoMapper.selectFsUserCourseVideoPageList(param);
        return list.stream().map(v -> {
            FsUserVideoListVO videoListVO = new FsUserVideoListVO();
            BeanUtils.copyProperties(v, videoListVO);
            return videoListVO;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ResponseResult<Boolean> isAddCompanyUser(FsUserCourseAddCompanyUserParam param) {
        logger.info("=======================进入个微-判断是否添加客服===========================，入参：{}",param);
        //查询用户
        FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
        if (fsUser == null){
            return ResponseResult.fail(404,"当前用户信息不存在");
        }

        //判断该销售是否存在
        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
        if (companyUser == null){
            return ResponseResult.fail(405,"当前销售不存在");
        }

        //判断：1、如果没有绑定销售，就返回给客服的微信图片;
        //2、如果只绑定了当前销售，需要添加看课记录（正常流程）；
        //3、以上都不是，则标识重粉，需要加入关系表，并打上重粉标签
        if(fsUser.getCompanyUserId() == null) {
            return ResponseResult.fail(BizResponseEnum.DATA_NOT_EXIST, getCompanyUserQRCode(companyUser));
        }

        // 如果开启了黑名单审核，需要提示
        if(fsUser.getStatus() == 0) {
//            return ResponseResult.fail(505, "管理开启了会员审核，请等待审核");
            return ResponseResult.fail(BizResponseEnum.WAIT_APPROVAL,getCompanyUserQRCode(companyUser));
        }

        //查询看课记录
//        FsCourseWatchLog watchCourseVideo = courseWatchLogMapper.getWatchCourseVideoByFsUser(param.getUserId(), param.getVideoId(), param.getCompanyUserId());
        FsCourseWatchLog watchCourseVideo = courseWatchLogMapper.getCourseWatchLogByUser(param.getUserId(), param.getVideoId());
        // 获取课程所属项目id
        FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
        Long courseProject = null;
        if(fsUserCourse != null){
            courseProject = fsUserCourse.getProject();
        }

        //添加判断：该用户是否已经存在此课程的看课记录，并且看课记录的销售id不是传入的销售id
        if(watchCourseVideo != null){
            if(!watchCourseVideo.getCompanyUserId().equals(param.getCompanyUserId())) {
                //提示
                return ResponseResult.fail(504, "已看过其他销售分享的此课程，不能重复观看");
            }

            FsCourseWatchLog updateLog = new FsCourseWatchLog();
            updateLog.setPeriodId(param.getPeriodId());
            updateLog.setProject(courseProject);
            updateLog.setUpdateTime(new Date());
            courseWatchLogMapper.updateFsCourseWatchLog(updateLog);
        } else {
            FsCourseWatchLog fsCourseWatchLog = new FsCourseWatchLog();
            BeanUtils.copyProperties(param, fsCourseWatchLog);
            fsCourseWatchLog.setSendType(1);
            fsCourseWatchLog.setDuration(0L);
            fsCourseWatchLog.setCreateTime(new Date());
            fsCourseWatchLog.setLogType(1);
            fsCourseWatchLog.setProject(courseProject);
            courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
        }

        // 判断是否重粉
        if(!companyUser.getUserId().equals(fsUser.getCompanyUserId())){
            FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
            fsUserCompanyUser.setIsRepeatFans(1);
            fsUserCompanyUser.setUserId(param.getUserId());
            fsUserCompanyUser.setCompanyId(param.getCompanyId());
            fsUserCompanyUser.setCompanyUserId(param.getCompanyUserId());
            QueryWrapper<FsUserCompanyUser> queryWrapper = new QueryWrapper<FsUserCompanyUser>().eq("user_id", param.getUserId()).eq("company_user_id", param.getCompanyUserId());
            Integer i = fsUserCompanyUserMapper.selectCount(queryWrapper);
            if(i == 0) {
                fsUserCompanyUserMapper.insertFsUserCompanyUser(fsUserCompanyUser);
            }

            // 打上重粉标签
            FsUserCourseBeMemberParam fsUserCourseBeMemberParam = new FsUserCourseBeMemberParam();
            fsUserCourseBeMemberParam.setUserId(param.getUserId());
            fsUserCourseBeMemberParam.setCompanyId(param.getCompanyId());
            fsUserCourseBeMemberParam.setCompanyUserId(param.getCompanyUserId());
            fsUserService.setRepeatFansTag(fsUserCourseBeMemberParam);
        }
        return ResponseResult.ok(Boolean.TRUE);
    }

    private String getCompanyUserQRCode(CompanyUser companyUser) {
        String companyUserQRCode;
        if(StringUtils.isNotEmpty(companyUser.getQrCodeWeixin())){
             companyUserQRCode = companyUser.getQrCodeWeixin();
        } else {
            String json = configService.selectConfigByKey("course.config");
            CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
             companyUserQRCode = config.getCompanyUserQRCode();
        }
        return companyUserQRCode;
    }

    @Override
    public ResponseResult<FsUserCourseVideoLinkDetailsVO> getLinkCourseVideoDetails(FsUserCourseVideoLinkParam param) {
//        FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
//        periodDays.setVideoId(param.getVideoId());
//        periodDays.setPeriodId(param.getPeriodId());
//        //正常情况是只能查询到一条，之前可能存在重复的脏数据，暂使用查询list的方式
//        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
//        if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
//            periodDays = fsUserCoursePeriodDays.get(0);
//        }
//        if(periodDays.getStatus() != 1){
//            return ResponseResult.fail(403, "当前课程未开始或已结束，暂不能看课");
//        }

        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        // 1、获取视频详情、问题详情
        ResponseResult<FsUserCourseVideoDetailsVO> videoDetails = this.getVideoDetails(param.getVideoId());
        FsUserCourseVideoDetailsVO courseVideoDetails = videoDetails.getData() != null ? videoDetails.getData() : null;

        //课程logo
        if (param.getPeriodId()!=null){
            FsUserCoursePeriod fsUserCoursePeriod = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(param.getPeriodId());
            if (fsUserCoursePeriod!=null){
                config.setCourseLogo(fsUserCoursePeriod.getCourseLogo());
            }
        }

        Long duration = 0L;
        long tipsTime = 0L;
        int isFinish = 0;
        FsUserCourseVideoLinkDetailsVO vo = new FsUserCourseVideoLinkDetailsVO();
        vo.setCourseVideoDetails(courseVideoDetails);
        vo.setCourseConfig(config);
        vo.setIsFinish(isFinish);
        vo.setPlayDuration(duration);

        //2、判断链接类型
        if (param.getLinkType() != null && param.getLinkType() == 1) {
            ResponseResult.ok(vo);
        }
        // 从Redis中获取用户目前的观看时长
        String redisKey = "h5wxuser:watch:duration:" + param.getFsUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
        String durationCurrent = redisCache.getCacheObject(redisKey);

        //3、获取看课记录
        FsCourseWatchLog watchLog = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getFsUserId(), param.getCompanyUserId());
        if (durationCurrent != null) {
            duration = Long.parseLong(durationCurrent);
        } else {
            duration = Objects.isNull(watchLog) ? 0 : watchLog.getDuration();
        }
//
//        if (course.getDuration()!=null){
//            tipsTime = course.getDuration()/2;
//        }
        //判断是否完课
        if (watchLog!=null && watchLog.getLogType() == 2) {
            isFinish = 1;
        }

        //将视频时长也存到redis
        String videoRedisKey = "h5wxuser:video:duration:" + param.getVideoId();
        Long videoDuration = redisCache.getCacheObject(videoRedisKey);
        if (videoDuration == null) {
            redisCache.setCacheObject(videoRedisKey, courseVideoDetails != null ? courseVideoDetails.getDuration() != null ? courseVideoDetails.getDuration() : 0 : 0);
        }
        vo.setIsFinish(isFinish);
        vo.setPlayDuration(duration);
        //判断营期的课程状态是否是进行中
        if(param.getId() != null){
            FsUserCoursePeriodDays days = fsUserCoursePeriodDaysMapper.selectById(param.getId());

            // 查询销售设置的看课时间
            LocalDateTime companyUserStartDateTime = null;
            LocalDateTime companyUserEndDateTime = null;

            List<CompanyUserTimeQueryParam> queryList = new ArrayList<>();
            CompanyUserTimeQueryParam query = new CompanyUserTimeQueryParam();
            query.setPeriodId(param.getPeriodId());
            query.setCourseId(param.getCourseId());
            query.setVideoId(param.getVideoId());
            query.setCompanyUserId(param.getCompanyUserId());
            queryList.add(query);
            List<FsUserCourseCompanyUserTime> fsUserCourseCompanyUserTimes = companyUserTimeMapper.batchSelectByParams(queryList);

            if(CollectionUtils.isNotEmpty(fsUserCourseCompanyUserTimes)){
                FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime = fsUserCourseCompanyUserTimes.get(0);
                Date cuStartDateTime = fsUserCourseCompanyUserTime.getStartDateTime();
                Date cuEndDateTime = fsUserCourseCompanyUserTime.getEndDateTime();

                if(cuStartDateTime != null){
                    Instant instant = cuStartDateTime.toInstant();
                    ZoneId zoneId = ZoneId.systemDefault();
                    companyUserStartDateTime = instant.atZone(zoneId).toLocalDateTime();
                }

                if(cuEndDateTime != null){
                    Instant instant = cuEndDateTime.toInstant();
                    ZoneId zoneId = ZoneId.systemDefault();
                    companyUserEndDateTime = instant.atZone(zoneId).toLocalDateTime();
                }
            }
            vo.setStartDateTime(companyUserStartDateTime != null ? companyUserStartDateTime : days.getStartDateTime());
            vo.setEndDateTime(companyUserEndDateTime != null ? companyUserEndDateTime : days.getEndDateTime());
            vo.setRang(DateUtil.isWithinRangeSafe(LocalDateTime.now(),
                    companyUserStartDateTime != null ? companyUserStartDateTime : days.getStartDateTime(),
                    companyUserEndDateTime != null ? companyUserEndDateTime : days.getEndDateTime())
                    && days.getStatus() == 1);
        }
        return ResponseResult.ok(vo);
    }

    @Override
    public R addWatchLogByLink(FsUserCourseAddCompanyUserParam param) {

        return null;
    }

    @Override
    public R updateWatchDurationWx(FsUserCourseVideoUParam param) {
        //临时短链不做记录
        if (param.getLinkType() != null && param.getLinkType() == 1){
            return R.ok();
        }

        // 从Redis中获取观看时长
        String redisKey = "h5wxuser:watch:duration:" + param.getUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
        log.info("看课redis缓存key：{}", redisKey);
        try {
            String durationStr = redisCache.getCacheObject(redisKey);
            log.info("看课记录：{}", durationStr);
            long duration = durationStr != null ? Long.parseLong(durationStr) : 0L;

            // 更新Redis中的观看时长
            if (param.getDuration() != null && param.getDuration() > duration) {
                //24小时过期
                redisCache.setCacheObject(redisKey, param.getDuration().toString(),2,TimeUnit.HOURS);
            }

            //更新缓存中的心跳时间
            updateHeartbeatWx(param);
            return R.ok();
        } catch (Exception e) {
            logger.error("更新看课时长失败：{}", redisKey, e.getMessage());
            return R.error("更新看课时长失败");
        }
    }

    @Override
    public void updates(CourseVideoUpdates vo) {
        fsUserCourseVideoMapper.updates(vo);
    }

    @Override
    public void batchSaveVideo(BatchVideoSvae vo) {
        List<FsVideoResource> videoResourceList = fsVideoResourceMapper.selectBatchIds(vo.getIds());
        FsUserCourseVideo param = new FsUserCourseVideo();
        param.setCourseId(vo.getCourseId());
        List<FsUserCourseVideo> videoList = selectFsUserCourseVideoList(param);
        AtomicLong i = new AtomicLong(videoList.size() + 1);
        String json = configService.selectConfigByKey("course.config");
        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);

        List<FsUserCourseVideo> collect = videoResourceList.stream().map(e -> {
            FsUserCourseVideo entity = new FsUserCourseVideo();
            entity.setTitle(e.getFileName());
            entity.setVideoUrl(e.getVideoUrl());
            entity.setThumbnail(e.getThumbnail());
            entity.setDuration(e.getDuration().longValue());
            entity.setCourseId(vo.getCourseId());
            entity.setStatus(3L);
            entity.setCourseSort(i.getAndIncrement());
            entity.setFileName(e.getFileName());
            entity.setQuestionBankId(e.getProjectIds());
            entity.setLineOne(e.getLine1());
            entity.setLineTwo(e.getLine2());
            entity.setLineThree(e.getLine3());
            entity.setRedPacketMoney(config.getRedPackageMoney());
            entity.setFileSize(e.getFileSize());
            entity.setFileKey(e.getFileKey());
            entity.setIsTranscode(0);
            return entity;
        }).collect(Collectors.toList());
        fsUserCourseVideoMapper.insertBatchFsUserCourseVideo(collect);
    }

    @Override
    public void batchUpdateRed(List<BatchRedUpdate> list) {
        list.forEach(e -> {
            fsUserCourseVideoMapper.updateRedPacketMoney(e.getVideoId(), e.getRedPacketMoney());
        });
    }

    /**
     * 获取选项列表
     * @param params    参数
     * @return  list
     */
    @Override
    public List<OptionsVO> selectVideoListByMap(Map<String, Object> params) {
        return fsUserCourseVideoMapper.selectVideoListByMap(params);
    }

    @Override
    public List<FsCourseVideoListBySidebarVO> getFsCourseVideoListBySidebar(FsCourseListBySidebarParam param) {
        return fsUserCourseVideoMapper.getFsCourseVideoListBySidebar(param);
    }

    @Override
    public R createMiniLink(FsCourseLinkMiniParam param) {
        QwExternalContact qwExternalContact = qwExternalContactMapper.selectById(param.getExtId());
        if (Objects.isNull(qwExternalContact)) {
            return R.error("客户不存在");
        }
        QwUser qwUser = qwUserMapper.selectById(qwExternalContact.getQwUserId());
        if (Objects.isNull(qwUser) || Objects.isNull(qwUser.getCompanyId()) || Objects.isNull(qwUser.getCompanyUserId())){
            return R.error("员工未绑定 销售公司 或 销售 请先绑定");
        }

        QwCompany qwCompany = qwCompanyService.selectQwCompanyByCorpId(qwUser.getCorpId());
        if (Objects.isNull(qwCompany)) {
            return R.error().put("msg","企业不存在，请联系管理员");
        }

        //看课记录
        addWatchLogIfNeeded(param.getVideoId(), param.getCourseId(), qwExternalContact.getFsUserId(), qwUser, qwExternalContact.getId());

        //生成小程序链接
        String linkByMiniApp = createLinkByMiniApp(new Date(), param.getCourseId(), param.getVideoId(), qwUser, qwExternalContact.getId(),2,null);
        return R.ok().put("data", linkByMiniApp);
    }

    /**
     * 查询课程列表
     * @param params 参数
     * @return  list
     */
    @Override
    public List<FsUserCourseVideoPageListVO> selectCourseVideoListByMap(Map<String, Object> params) {
        return fsUserCourseVideoMapper.selectFsUserCourseVideoListByMap(params);
    }

    @Override
    public ResponseResult<Boolean> setWatchCourseTime(List<FsWatchCourseTimeParam> paramList) {
        if (CollectionUtils.isEmpty(paramList)) {
            return ResponseResult.fail(400, "参数不能为空");
        }

        // 1. 查询参数
        List<CompanyUserTimeQueryParam> queryList = paramList.stream()
                .map(param -> {
                    CompanyUserTimeQueryParam query = new CompanyUserTimeQueryParam();
                    query.setPeriodId(param.getPeriodId());
                    query.setCourseId(param.getCourseId());
                    query.setVideoId(param.getVideoId());
                    query.setCompanyUserId(param.getCompanyUserId());
                    return query;
                })
                .collect(Collectors.toList());

        // 2. 批量查询现有的记录
        List<FsUserCourseCompanyUserTime> existingRecords = companyUserTimeMapper.batchSelectByParams(queryList);
        Map<String, FsUserCourseCompanyUserTime> existingMap = existingRecords.stream()
                .collect(Collectors.toMap(record -> getKey(record.getPeriodId(), record.getCourseId(), record.getVideoId(), record.getCompanyUserId()),
                        record -> record));

        // 3. 分离需要更新和插入的记录
        List<FsUserCourseCompanyUserTime> toUpdate = new ArrayList<>();
        List<FsUserCourseCompanyUserTime> toInsert = new ArrayList<>();
        Date now = DateUtils.getNowDate();

        for (FsWatchCourseTimeParam param : paramList) {
            String key = getKey(param.getPeriodId(), param.getCourseId(), param.getVideoId(), param.getCompanyUserId());
            FsUserCourseCompanyUserTime record = existingMap.get(key);

            if (record != null) {
                // 需要更新
                record.setStartDateTime(param.getStartDateTime());
                record.setEndDateTime(param.getEndDateTime());
                record.setUpdateTime(now);
                toUpdate.add(record);
            } else {
                // 需要插入
                FsUserCourseCompanyUserTime newRecord = new FsUserCourseCompanyUserTime();
                newRecord.setPeriodId(param.getPeriodId());
                newRecord.setCourseId(param.getCourseId());
                newRecord.setVideoId(param.getVideoId());
                newRecord.setCompanyUserId(param.getCompanyUserId());
                newRecord.setCompanyId(param.getCompanyId());
                newRecord.setStartDateTime(param.getStartDateTime());
                newRecord.setEndDateTime(param.getEndDateTime());
                newRecord.setCreateTime(now);
                toInsert.add(newRecord);
            }
        }

        // 4. 执行批量更新和插入
        if (!toUpdate.isEmpty()) {
            companyUserTimeMapper.batchUpdate(toUpdate);
        }
        if (!toInsert.isEmpty()) {
            companyUserTimeMapper.batchInsert(toInsert);
        }

        return ResponseResult.ok();
    }

    /**
     * 生成唯一键
     */
    private String getKey(Long periodId, Long courseId, Long videoId, Long companyUserId) {
        return String.format("%d_%d_%d_%d", periodId, courseId, videoId, companyUserId);
    }

    private String createLinkByMiniApp(Date sendTime, Long courseId, Long videoId,
                                       QwUser qwUser, Long externalId,int type,String domainName) {
        FsCourseLink link = new FsCourseLink();
        link.setCompanyId(qwUser.getCompanyId());
        link.setQwUserId(String.valueOf(qwUser.getId()));
        link.setCompanyUserId(qwUser.getCompanyUserId());
        link.setVideoId(videoId);
        link.setCorpId(qwUser.getCorpId());
        link.setCourseId(courseId);
        link.setQwExternalId(externalId);

        if (type == 1) {
            link.setLinkType(0);
        }else {
            link.setLinkType(3);
        }

        String randomString = generateRandomStringWithLock();
        if (StringUtil.strIsNullOrEmpty(randomString)){
            link.setLink(UUID.randomUUID().toString().replace("-", ""));
        }else {
            link.setLink(randomString);
        }

        link.setCreateTime(sendTime);

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

        String courseJson = JSON.toJSONString(courseMap);

        String realLinkFull;

        if (type == 1) {
            realLinkFull = REAL_LINK_PREFIX + courseJson;
        }else {
            realLinkFull = miniappRealLink + courseJson;
        }

        link.setRealLink(realLinkFull);

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

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

        if (type==1){
            return domainName + SHORT_LINK_PREFIX + link.getLink();
        }else {
            return link.getRealLink();
        }
    }

    // 插入观看记录
    private void addWatchLogIfNeeded(Long videoId, Long courseId,
                                     Long fsUserId, QwUser qwUser,Long externalId) {

        try {
            FsCourseWatchLog watchLog = new FsCourseWatchLog();
            watchLog.setVideoId(videoId);
            watchLog.setQwExternalContactId(externalId);
            watchLog.setSendType(2);
            watchLog.setQwUserId(String.valueOf(qwUser.getId()));
            watchLog.setDuration(0L);
            watchLog.setCourseId(courseId);
            watchLog.setCompanyUserId(qwUser.getCompanyUserId());
            watchLog.setCompanyId(qwUser.getCompanyId());
            watchLog.setCreateTime(new Date());
            watchLog.setUpdateTime(new Date());
            watchLog.setLogType(3);

            if (fsUserId == null) {
                fsUserId=0L;
            }
            watchLog.setUserId(fsUserId);

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

    //会员-更新心跳时间
    public void updateHeartbeatWx(FsUserCourseVideoUParam param) {
        String redisKey = "h5wxuser:watch:heartbeat:" + param.getUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
        redisCache.setCacheObject(redisKey, LocalDateTime.now().toString());
        // 设置 Redis 记录的过期时间（例如 5 分钟）
        redisCache.expire(redisKey, 300, TimeUnit.SECONDS);
    }
}
