package com.fs.course.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fs.common.core.domain.entity.SysDictData;
import com.fs.common.core.domain.R;
import com.fs.common.core.redis.RedisCache;
import com.fs.common.exception.CustomException;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.date.DateUtil;
import com.fs.common.utils.date.TimeTypeEnum;
import com.fs.course.domain.FsUserCoursePeriod;
import com.fs.course.domain.FsUserCoursePeriodDays;
import com.fs.course.domain.FsUserCourseVideo;
import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
import com.fs.course.mapper.FsUserCoursePeriodMapper;
import com.fs.course.mapper.FsUserCourseVideoMapper;
import com.fs.course.mapper.FsUserCourseVideoRedPackageMapper;
import com.fs.course.param.BatchAddCourseSectionParam;
import com.fs.course.param.PeriodStatisticCountParam;
import com.fs.course.service.IFsUserCoursePeriodDaysService;
import com.fs.course.service.IFsUserCoursePeriodService;
import com.fs.course.vo.FsCourseStaticsCountVO;
import com.fs.course.vo.FsUserCoursePeriodVO;
import com.hc.openapi.tool.fastjson.JSON;
import com.hc.openapi.tool.fastjson.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 会员营期Service业务层处理
 *
 * @author fs
 * @date 2025-04-15
 */
@Service
public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
{
    @Autowired
    private FsUserCoursePeriodMapper fsUserCoursePeriodMapper;
    @Resource
    RedisCache redisCache;
    @Resource
    private FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;
    @Resource
    private FsUserCourseVideoRedPackageMapper fsUserCourseVideoRedPackageMapper;
    @Autowired
    private FsUserCourseVideoMapper fsUserCourseVideoMapper;
    @Autowired
    private IFsUserCoursePeriodDaysService fsUserCoursePeriodDaysService;
    /**
     * 查询会员营期
     *
     * @param periodId 会员营期ID
     * @return 会员营期
     */
    @Override
    public FsUserCoursePeriod selectFsUserCoursePeriodById(Long periodId)
    {
        return fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(periodId);
    }

    /**
     * 查询会员营期列表
     *
     * @param fsUserCoursePeriod 会员营期
     * @return 会员营期
     */
    @Override
    public List<FsUserCoursePeriod> selectFsUserCoursePeriodList(FsUserCoursePeriod fsUserCoursePeriod)
    {
        return fsUserCoursePeriodMapper.selectFsUserCoursePeriodList(fsUserCoursePeriod);
    }

    /**
     * 新增会员营期
     *
     * @param fsUserCoursePeriod 会员营期
     * @return 结果
     */
    @Override
    public int insertFsUserCoursePeriod(FsUserCoursePeriod fsUserCoursePeriod)
    {
        fsUserCoursePeriod.setCreateTime(LocalDateTime.now());

        // 设置营期状态：如果开启自由模式，设置为进行中（status=2）
        if (fsUserCoursePeriod.getFreeMode() != null && fsUserCoursePeriod.getFreeMode() == 1) {
            // 自由模式：营期状态为进行中
            fsUserCoursePeriod.setPeriodStatus(2L);
        } else {
            // 固定模式：按照时间设置状态
            if(LocalDate.now().isBefore(fsUserCoursePeriod.getPeriodStartingTime())){
                fsUserCoursePeriod.setPeriodStatus(1L);
            } else if(LocalDate.now().isAfter(fsUserCoursePeriod.getPeriodEndTime())){
                fsUserCoursePeriod.setPeriodStatus(3L);
            } else{
                fsUserCoursePeriod.setPeriodStatus(2L);
            }
        }
        return fsUserCoursePeriodMapper.insertFsUserCoursePeriod(fsUserCoursePeriod);
    }

    /**
     * 修改会员营期
     *
     * @param fsUserCoursePeriod 会员营期
     * @return 结果
     */
    @Override
    public int updateFsUserCoursePeriod(FsUserCoursePeriod fsUserCoursePeriod) {
        // 1. 查询原始数据
        fsUserCoursePeriod.setUpdateTime(LocalDateTime.now());

        // 设置营期状态：如果开启自由模式，设置为进行中（status=2）
        if (fsUserCoursePeriod.getFreeMode() != null && fsUserCoursePeriod.getFreeMode() == 1) {
            // 自由模式：营期状态为进行中
            fsUserCoursePeriod.setPeriodStatus(2L);
        } else {
            // 固定模式：按照时间设置状态
            if(LocalDate.now().isBefore(fsUserCoursePeriod.getPeriodStartingTime())){
                fsUserCoursePeriod.setPeriodStatus(1L);
            } else if(LocalDate.now().isAfter(fsUserCoursePeriod.getPeriodEndTime())){
                fsUserCoursePeriod.setPeriodStatus(3L);
            } else{
                fsUserCoursePeriod.setPeriodStatus(2L);
            }
        }

        FsUserCoursePeriod fsUserCoursePeriod1 = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(fsUserCoursePeriod.getPeriodId());
        if (!fsUserCoursePeriod1.getTrainingCampId().equals(fsUserCoursePeriod.getTrainingCampId())){
            throw new CustomException("参数错误，请刷新后重试！");
        }
        int flag = fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);

        // 2. 判定是否变更过开始时间（periodStartingTime）
        if (fsUserCoursePeriod1.getPeriodStartingTime().equals(fsUserCoursePeriod.getPeriodStartingTime())) {
            // 如果开始时间没有变化，直接返回
            return flag;
        }

        // 3. 计算课程时间差（以天数为单位）
        long daysDifference = ChronoUnit.DAYS.between(fsUserCoursePeriod1.getPeriodStartingTime(), fsUserCoursePeriod.getPeriodStartingTime());

        // 4. 获取课程天数并进行时间调整
        FsUserCoursePeriodDays fsUserCoursePeriodDays = new FsUserCoursePeriodDays();
        fsUserCoursePeriodDays.setPeriodId(fsUserCoursePeriod1.getPeriodId());
        List<FsUserCoursePeriodDays> list = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(fsUserCoursePeriodDays);

        // 对每个课程日期进行时间增加
        LocalDateTime now = LocalDateTime.now();
        for (FsUserCoursePeriodDays coursePeriodDays : list) {
            // 将课程的日期按照差值天数进行调整
            LocalDate adjustedDate = coursePeriodDays.getDayDate().plusDays(daysDifference);
            LocalDateTime startDateTime = coursePeriodDays.getStartDateTime().plusDays(daysDifference);
            LocalDateTime endDateTime = coursePeriodDays.getEndDateTime().plusDays(daysDifference);
            LocalDateTime lastJsonTime = coursePeriodDays.getLastJoinTime().plusDays(daysDifference);
            coursePeriodDays.setDayDate(adjustedDate);
            coursePeriodDays.setStartDateTime(startDateTime);
            coursePeriodDays.setEndDateTime(endDateTime);
            coursePeriodDays.setLastJoinTime(lastJsonTime);

            // 根据调整后的时间重新计算课程状态（仅对非自由模式营期）
            if (fsUserCoursePeriod.getFreeMode() == null || fsUserCoursePeriod.getFreeMode() != 1) {
                if (now.isBefore(startDateTime)) {
                    // 未开始
                    coursePeriodDays.setStatus(0);
                } else if (now.isAfter(endDateTime)) {
                    // 已结束
                    coursePeriodDays.setStatus(2);
                } else {
                    // 进行中
                    coursePeriodDays.setStatus(1);
                }
            }

            fsUserCoursePeriodDaysMapper.updateFsUserCoursePeriodDays(coursePeriodDays); // 更新数据库中的课程日期
        }

        return flag;
    }

    /**
     * 批量删除会员营期
     *
     * @param periodIds 需要删除的会员营期ID
     * @return 结果
     */
    @Override
    public int deleteFsUserCoursePeriodByIds(Long[] periodIds)
    {
        if (checkPeriodStatus(periodIds)) {
            throw new ServiceException("存在进行中的营期，不允许删除");
        }
        int flag = fsUserCoursePeriodMapper.updateBatchDelFlag(periodIds,1);
        //删除课程
        Set<Long> set = Arrays.asList(periodIds).stream().collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(set)){
            return flag;
        }
        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectCourseVideoList(set);
        List<Long> periodDayIds = fsUserCoursePeriodDays.stream().map(FsUserCoursePeriodDays::getId).collect(Collectors.toList());
        if(!periodDayIds.isEmpty()){
            fsUserCoursePeriodDaysMapper.updateBatchDelFlag(periodDayIds.toArray(new Long[0]),1);
            //删除红包记录（修改状态）
            //fsUserCourseVideoRedPackageMapper.updateBatchDelFlag(videoIds.toArray(new Long[0]),1);
            //直接删除
            fsUserCourseVideoRedPackageMapper.deleteBatchByPeriodIds(periodIds);
        }
        return flag;
    }
    private boolean checkPeriodStatus(Long[] ids) {
        LocalDate currentDate = LocalDate.now(); // 2025-06-30
        Set<Long> idSet = Arrays.stream(ids).collect(Collectors.toSet());
        List<FsUserCoursePeriod> list = fsUserCoursePeriodMapper.selectFsUserCoursePeriodsByIds(idSet);

        List<FsUserCoursePeriod> filteredList = list.stream()
                .filter(period -> {
                    boolean isActive = Long.valueOf(2).equals(period.getPeriodStatus());
                    return isActive;
                })
                .collect(Collectors.toList());

        return !filteredList.isEmpty();
    }

    /**
     * 删除会员营期信息
     *
     * @param periodId 会员营期ID
     * @return 结果
     */
    @Override
    public int deleteFsUserCoursePeriodById(Long periodId)
    {
        return fsUserCoursePeriodMapper.deleteFsUserCoursePeriodById(periodId);
    }

    @Override
    public List<FsUserCoursePeriodVO> selectFsUserCoursePeriodPage(FsUserCoursePeriod fsUserCoursePeriod) {
        return fsUserCoursePeriodMapper.selectFsUserCoursePeriodPage(fsUserCoursePeriod);
    }

    /**
     * 结束营期
     * @param id    营期ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void closePeriod(Long id) {
        // 修改营期结束时间
        FsUserCoursePeriod fsUserCoursePeriod = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(id);
        if (Objects.isNull(fsUserCoursePeriod)) {
            throw new ServiceException("结束营期失败：营期不存在");
        }

        if (fsUserCoursePeriod.getPeriodStatus() == 1) {
            throw new ServiceException("结束营期失败：营期未开始不能进行结束操作！");
        }

        if (fsUserCoursePeriod.getPeriodStatus() == 3) {
            throw new ServiceException("结束营期失败：营期已结束不能进行结束操作！");
        }

        fsUserCoursePeriod.setPeriodEndTime(LocalDate.now());
        fsUserCoursePeriod.setPeriodStatus(Long.valueOf(3));
        fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);

        // 修改大于当前时间的课程状态
        Wrapper<FsUserCoursePeriodDays> updateWrapper = Wrappers.<FsUserCoursePeriodDays>lambdaUpdate()
                .set(FsUserCoursePeriodDays::getStatus, 2)
                .eq(FsUserCoursePeriodDays::getPeriodId, fsUserCoursePeriod.getPeriodId())
                .eq(FsUserCoursePeriodDays::getStatus, 0)
                .gt(FsUserCoursePeriodDays::getDayDate, LocalDate.now());
        fsUserCoursePeriodDaysMapper.update(null, updateWrapper);
    }

    /**
     * 更新营期状态
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changePeriodStatus() {
        // 开营
        fsUserCoursePeriodMapper.startPeriod(LocalDate.now());

        // 关营
        fsUserCoursePeriodMapper.endPeriod(LocalDate.now());
    }
    @Override
    public FsCourseStaticsCountVO periodCourseStatisticCount(PeriodStatisticCountParam param) {
        String redisKey = "user:trainingCampId:periodId:" + param.getUserId() + ":" + param.getTrainingCampId();
        if (ObjectUtil.isNotEmpty(param.getPeriodId())){
            redisKey=redisKey+":"+param.getPeriodId();
        }
        FsCourseStaticsCountVO durationStr = redisCache.getCacheObject(redisKey);
        if (ObjectUtil.isNotEmpty(durationStr)){
            return durationStr;
        }
        FsCourseStaticsCountVO fsCourseStaticsCountVO = new FsCourseStaticsCountVO();
        try {
            Long courseCompleteNum = fsUserCoursePeriodMapper.setlectCourseCompleteNum(param);
            fsCourseStaticsCountVO.setCourseCompleteNum(courseCompleteNum != null ? courseCompleteNum : 0L);

            Long courseWatchNum = fsUserCoursePeriodMapper.setlectCourseWatchNum(param);
            fsCourseStaticsCountVO.setCourseWatchNum(courseWatchNum != null ? courseWatchNum : 0L);

            Long redPacketCount = fsUserCoursePeriodMapper.setlectRedPacketCount(param);
            fsCourseStaticsCountVO.setRedPacketCount(redPacketCount != null ? redPacketCount : 0L);

            BigDecimal redPacketAmount = fsUserCoursePeriodMapper.setlectRedPacketAmount(param);
            fsCourseStaticsCountVO.setRedPacketAmount(redPacketAmount != null ? redPacketAmount : BigDecimal.ZERO);

            Long correctAnswerNum = fsUserCoursePeriodMapper.setlectCorrectAnswerNum(param);
            fsCourseStaticsCountVO.setCorrectAnswerNum(correctAnswerNum != null ? correctAnswerNum : 0L);
            redisCache.setCacheObject(redisKey,fsCourseStaticsCountVO);
            // 设置 Redis 记录的过期时间（例如 5 分钟）
            redisCache.expire(redisKey, 600, TimeUnit.SECONDS);
            return fsCourseStaticsCountVO;

        } catch (Exception e) {
            return fsCourseStaticsCountVO;
        }
    }

    @Override
    public List<FsUserCoursePeriod> selectFsPeriodlist(PeriodStatisticCountParam param) {
        return fsUserCoursePeriodMapper.selectFsPeriodlist(param);
    }

    @Override
    public R insertFsUserCoursePeriodAndCourse(FsUserCoursePeriod fsUserCoursePeriod) {
        // 1. 参数校验：避免空指针和无效数据
        if (fsUserCoursePeriod == null
                || fsUserCoursePeriod.getCourseId() == null
                || fsUserCoursePeriod.getPeriodStartingTime() == null
                || fsUserCoursePeriod.getPeriodEndTime() == null) {
            return R.error("营期信息不完整");
        }
        // 2. 插入营期主表，直接判断结果（insert返回值通常为影响行数，无需单独用变量接收）
        if (insertFsUserCoursePeriod(fsUserCoursePeriod) <= 0) {
            return R.error("营期创建失败");
        }

        // 3. 查询关联的课程视频（简化查询参数构建）
        FsUserCourseVideo queryVideo = new FsUserCourseVideo();
        queryVideo.setCourseId(fsUserCoursePeriod.getCourseId());
        List<FsUserCourseVideo> courseVideos = fsUserCourseVideoMapper.selectFsUserCourseVideoListByCourseId(queryVideo);

        // 4. 批量添加课程小节（修复：改用批量添加方法，避免课次号倒序问题）
        if (!courseVideos.isEmpty()) {
            // 提取视频ID列表
            List<Long> videoIds = courseVideos.stream()
                    .map(FsUserCourseVideo::getVideoId)
                    .collect(Collectors.toList());

            // 构建批量添加参数
            BatchAddCourseSectionParam param = new BatchAddCourseSectionParam();
            param.setPeriodId(fsUserCoursePeriod.getPeriodId());
            param.setCourseId(fsUserCoursePeriod.getCourseId());
            param.setVideoIds(videoIds);
            param.setStartTime(LocalTime.MIDNIGHT);
            param.setEndDateTime(LocalTime.of(23, 59, 59));
            param.setJoinTime(LocalTime.of(23, 59, 59));
            param.setAutoSort(true); // 自动按courseSort排序
            param.setSkipDuplicate(true); // 跳过重复视频

            // 调用批量添加方法
            R result = fsUserCoursePeriodDaysService.batchAddCourseSections(param);
            if ((Integer)result.get("code") != 200) {
                return R.error("课程安排创建失败：" + result.get("msg"));
            }
        }
        return R.ok("营期及课程安排创建成功");
    }
    @Override
    public List<Long> selectCoursePeriodDaysByTime(String periodSTime, String periodETime,Long companyId) {
        return fsUserCoursePeriodMapper.selectCoursePeriodDaysByTime(periodSTime,periodETime,companyId);
    }

    @Override
    public List<Long> selectFsUserCoursePeriodListByPeriodId(List<Long> periodIds, Long companyId) {
        return fsUserCoursePeriodMapper.selectFsUserCoursePeriodListByPeriodId(periodIds,companyId);
    }

    @Override
    public int editIsNeedRegisterMember(FsUserCoursePeriod fsUserCoursePeriod,String companyId) {
        String currentValue = fsUserCoursePeriod.getIsNeedRegisterMember();

        if (currentValue.equals("0")) {
            // 移除指定的 companyId
            String updatedValue = Arrays.stream(currentValue.split(","))
                    .map(String::trim)
                    .filter(id -> !id.equals(companyId))
                    .collect(Collectors.joining(","));
            fsUserCoursePeriod.setIsNeedRegisterMember(updatedValue);
        } else {
            // 添加 companyId，并过滤掉 "0"
            String updatedValue = Arrays.stream(currentValue.split(","))
                    .map(String::trim)
                    .filter(id -> !id.equals("0")) // 清除 "0"
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(LinkedHashSet::new),
                            set -> {
                                set.add(companyId);
                                return String.join(",", set);
                            }
                    ));
            fsUserCoursePeriod.setIsNeedRegisterMember(updatedValue);
        }
        return fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);
    }

    @Override
    public List<SysDictData> selectFsUserCoursePeriodListLabel(FsUserCoursePeriod fsUserCoursePeriod) {
        return fsUserCoursePeriodMapper.selectFsUserCoursePeriodListLabel(fsUserCoursePeriod);
    }

    @Override
    public R copyFsUserCoursePeriodAndCourse(PeriodStatisticCountParam param) {
        if (param == null || param.getPeriodId() == null || param.getTrainingCampId() == null) {
            return R.error("营期信息不完整");
        }
        //通过现有的营期Id查询，并查询到对应的营期看课
        FsUserCoursePeriod fsUserCoursePeriod = selectFsUserCoursePeriodById(param.getPeriodId());
        if (fsUserCoursePeriod == null) {
            return R.error("未查询到当前营期");
        }
        //查询并复制当前营期所有的视频
        FsUserCoursePeriodDays fsUserCoursePeriodDays = new FsUserCoursePeriodDays();
        fsUserCoursePeriodDays.setPeriodId(param.getPeriodId());
        List<FsUserCoursePeriodDays> fsUserCoursePeriodDayslist = fsUserCoursePeriodDaysService.selectFsUserCoursePeriodDaysList(fsUserCoursePeriodDays);
        fsUserCoursePeriod.setTrainingCampId(param.getTrainingCampId());
        fsUserCoursePeriod.setPeriodId(null);
        if (insertFsUserCoursePeriod(fsUserCoursePeriod) <= 0) {
            return R.error("营期创建失败");
        }
        // 定义重复使用的时间常量
        LocalTime startTime = LocalTime.MIDNIGHT;
        LocalTime endTime = LocalTime.of(23, 59, 59);
        fsUserCoursePeriodDayslist.forEach(userCoursePeriodDays -> {
            userCoursePeriodDays.setPeriodId(fsUserCoursePeriod.getPeriodId());
            userCoursePeriodDays.setId(null);
            userCoursePeriodDays.setStartTime(startTime);
            userCoursePeriodDays.setEndTime1(endTime);
            userCoursePeriodDays.setJoinTime(endTime);
            userCoursePeriodDays.setVideoIds(Collections.singletonList(userCoursePeriodDays.getVideoId()));
            fsUserCoursePeriodDaysService.addCourse(userCoursePeriodDays);
        });
        return R.ok();

    }


    /**
     * @Description: 更新营期信息
     * @Param:
     * @Return:
     * @Author xgb
     * @Date 2025/12/19 10:52
     */
    @Override
    public int updatePeriod(FsUserCoursePeriod fsUserCoursePeriod, Long companyId) {
        Integer flag=fsUserCoursePeriod.getIsOpenRestReminder(); // 0-关闭 1-打开
        FsUserCoursePeriod period=fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(fsUserCoursePeriod.getPeriodId());
        if (period==null){
            return 0;
        }

        JSONObject jsonObject;
        if (StringUtils.isNotBlank(period.getIsOpenRestFlag())){
            jsonObject= JSON.parseObject(period.getIsOpenRestFlag());
            jsonObject.put(companyId.toString(),flag);
        }else {
            jsonObject=new JSONObject();
            jsonObject.put(companyId.toString(),flag);
        }

        fsUserCoursePeriod.setIsOpenRestFlag(jsonObject.toJSONString());

        return fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);
    }
}
