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.redis.RedisCache;
import com.fs.common.exception.CustomException;
import com.fs.common.exception.ServiceException;
import com.fs.course.domain.FsUserCoursePeriod;
import com.fs.course.domain.FsUserCoursePeriodDays;
import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
import com.fs.course.mapper.FsUserCoursePeriodMapper;
import com.fs.course.mapper.FsUserCourseVideoRedPackageMapper;
import com.fs.course.param.PeriodStatisticCountParam;
import com.fs.course.service.IFsUserCoursePeriodService;
import com.fs.course.vo.FsCourseStaticsCountVO;
import com.fs.course.vo.FsUserCoursePeriodVO;
import org.apache.commons.collections.CollectionUtils;
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.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;

    /**
     * 查询会员营期
     *
     * @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());
        // 设置营期状态
        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());

        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);

        // 对每个课程日期进行时间增加
        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);
            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());
        List<Long> videoIds = fsUserCoursePeriodDays.stream().map(FsUserCoursePeriodDays::getVideoId).collect(Collectors.toList());
        if(!periodDayIds.isEmpty()){
            fsUserCoursePeriodDaysMapper.updateBatchDelFlag(periodDayIds.toArray(new Long[0]),1);
            //删除红包记录（修改状态）
            //fsUserCourseVideoRedPackageMapper.updateBatchDelFlag(videoIds.toArray(new Long[0]),1);
            //直接删除
            fsUserCourseVideoRedPackageMapper.deleteBatchByVideoIds(videoIds.toArray(new Long[0]));
        }
        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 -> {
                    LocalDate startTime = period.getPeriodStartingTime();
                    LocalDate endTime = period.getPeriodEndTime();

                    boolean isActive = startTime != null && !startTime.isAfter(currentDate)
                            && (endTime == null || !endTime.isBefore(currentDate));

                    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());
        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 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) {
        return fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);
    }

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