package com.fs.course.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fs.common.core.domain.R;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.PubFun;
import com.fs.common.utils.date.DateUtil;
import com.fs.common.utils.date.TimeTypeEnum;
import com.fs.company.domain.CompanyDomain;
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.FsUserCourseVideoRedPackageMapper;
import com.fs.course.param.CompanyRedPacketParam;
import com.fs.course.param.CourseAnalysisParam;
import com.fs.course.param.PeriodCountParam;
import com.fs.course.service.IFsUserCoursePeriodDaysService;
import com.fs.course.service.IFsUserCourseVideoService;
import com.fs.course.vo.FsPeriodCountVO;
import com.fs.course.vo.PeriodRedPacketVO;
import com.fs.course.vo.UpdateCourseTimeVo;
import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
import com.fs.his.mapper.FsUserMapper;
import com.fs.his.vo.OptionsVO;
import com.fs.sop.domain.QwSopTempRules;
import com.fs.system.domain.SysConfig;
import com.fs.system.mapper.SysConfigMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 营期课程Service业务层处理
 *
 * @author fs
 * @date 2025-04-16
 */
@Service
@AllArgsConstructor
@Slf4j
public class FsUserCoursePeriodDaysServiceImpl extends ServiceImpl<FsUserCoursePeriodDaysMapper, FsUserCoursePeriodDays> implements IFsUserCoursePeriodDaysService {

    private final FsUserCoursePeriodMapper fsUserCoursePeriodMapper;

    private final FsUserMapper fsUserMapper;
    private final SysConfigMapper sysConfigMapper;

    private final FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;
    private final IFsUserCourseVideoService fsUserCourseVideoService;

    @Autowired
    private FsUserCourseVideoRedPackageMapper fsUserCourseVideoRedPackageMapper;
    /**
     * 查询营期课程
     *
     * @param id 营期课程主键
     * @return 营期课程
     */
    @Override
    public FsUserCoursePeriodDays selectFsUserCoursePeriodDaysById(Long id)
    {
        return baseMapper.selectFsUserCoursePeriodDaysById(id);
    }

    /**
     * 查询营期课程列表
     *
     * @param fsUserCoursePeriodDays 营期课程
     * @return 营期课程
     */
    @Override
    public List<FsUserCoursePeriodDays> selectFsUserCoursePeriodDaysList(FsUserCoursePeriodDays fsUserCoursePeriodDays)
    {
        return baseMapper.selectFsUserCoursePeriodDaysList(fsUserCoursePeriodDays);
    }

    /**
     * 新增营期课程
     *
     * @param fsUserCoursePeriodDays 营期课程
     * @return 结果
     */
    @Override
    public int insertFsUserCoursePeriodDays(FsUserCoursePeriodDays fsUserCoursePeriodDays)
    {
        fsUserCoursePeriodDays.setCreateTime(DateUtils.getNowDate());
        return baseMapper.insert(fsUserCoursePeriodDays);
    }

    /**
     * 修改营期课程
     *
     * @param fsUserCoursePeriodDays 营期课程
     * @return 结果
     */
    @Override
    public int updateFsUserCoursePeriodDays(FsUserCoursePeriodDays fsUserCoursePeriodDays)
    {
        fsUserCoursePeriodDays.setUpdateTime(DateUtils.getNowDate());
        return baseMapper.updateById(fsUserCoursePeriodDays);
    }

    /**
     * 批量删除营期课程
     *
     * @param ids 需要删除的营期课程主键
     * @return 结果
     */
    @Override
    public int deleteFsUserCoursePeriodDaysByIds(Long[] ids)
    {
        int flag = 0;
        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectBatchIds(Arrays.asList(ids));
        List<Long> periodDayIds = fsUserCoursePeriodDays.stream().map(FsUserCoursePeriodDays::getId).collect(Collectors.toList());
        List<Long> getPeriodIds = fsUserCoursePeriodDays.stream().map(FsUserCoursePeriodDays::getPeriodId).collect(Collectors.toList());
        List<Long> videoIds = fsUserCoursePeriodDays.stream().map(FsUserCoursePeriodDays::getVideoId).collect(Collectors.toList());
        if(!periodDayIds.isEmpty()){
            flag = fsUserCoursePeriodDaysMapper.updateBatchDelFlag(periodDayIds.toArray(new Long[0]),1);
            //删除红包记录
            fsUserCourseVideoRedPackageMapper.deleteFsUserCourseVideoRedPackageByVedioIds(videoIds.toArray(new Long[0]),getPeriodIds.toArray(new Long[0]));
        }
        return flag;
    }

    /**
     * 删除营期课程信息
     *
     * @param id 营期课程主键
     * @return 结果
     */
    @Override
    public int deleteFsUserCoursePeriodDaysById(Long id)
    {
        return baseMapper.deleteFsUserCoursePeriodDaysById(id);
    }

    @Override
    public R addCourse(FsUserCoursePeriodDays entity) {
        FsUserCoursePeriod period = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(entity.getPeriodId());
        List<FsUserCoursePeriodDays> dayList = list(new QueryWrapper<FsUserCoursePeriodDays>().eq("period_id", period.getPeriodId()).eq("del_flag","0"));
        long days;
        if(period.getPeriodType() == 2){
            days = 1;
        }else{
            days = DateUtil.differenceTime(period.getPeriodStartingTime(), period.getPeriodEndTime(), TimeTypeEnum.DAY);
        }
        days++;
        if(dayList.size() + entity.getVideoIds().size() > days) return R.error("课程不能超过营期范围");
        if(dayList.stream().anyMatch(e -> entity.getVideoIds().contains(e.getVideoId()))) return R.error("不能添加相同章节");
        AtomicInteger i = new AtomicInteger(0);
        FsUserCourseVideo fsUserCourseVideo = new FsUserCourseVideo();
        fsUserCourseVideo.setCourseId(entity.getCourseId());
        List<FsUserCourseVideo> videoList = fsUserCourseVideoService.selectFsUserCourseVideoListByCourseId(fsUserCourseVideo);
        Map<Long, FsUserCourseVideo> videoMap = PubFun.listToMapByGroupObject(videoList, FsUserCourseVideo::getVideoId);
        List<FsUserCoursePeriodDays> collect = entity.getVideoIds().stream().map(e -> {
            FsUserCourseVideo video = videoMap.get(e);
            FsUserCoursePeriodDays day = new FsUserCoursePeriodDays();
            day.setPeriodId(entity.getPeriodId());
            day.setLesson(dayList.size() + i.getAndIncrement());
            day.setDayDate(period.getPeriodStartingTime().plusDays(day.getLesson()));
            day.setCourseId(entity.getCourseId());
            if(entity.getStartTime() != null){
                day.setStartDateTime(LocalDateTime.of(day.getDayDate(), entity.getStartTime()));
            }else if(video.getViewStartTime() != null){
                day.setStartDateTime(LocalDateTime.of(day.getDayDate(), video.getViewStartTime()));
            }
            if(entity.getEndTime1() != null){
                day.setEndDateTime(LocalDateTime.of(day.getDayDate(), entity.getEndTime1()));
            }else if(video.getViewEndTime() != null){
                day.setEndDateTime(LocalDateTime.of(day.getDayDate(), video.getViewEndTime()));
            }
            SysConfig config = sysConfigMapper.selectConfigByConfigKey("joinTime.switch.config");
            if (ObjectUtils.isNotEmpty(config)&&config.getConfigValue().equals("1")){
                entity.setJoinTime(entity.getEndTime1());
            }
            if(entity.getJoinTime() != null){
                day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), entity.getJoinTime()));
            }else if(video.getLastJoinTime() != null){
                day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), video.getLastJoinTime()));
            }
            day.setVideoId(e);
            day.setCreateTime(new Date());
            // 默认开启今天及以后的两天
            LocalDate compareDay = LocalDate.now().plusDays(1);
            if(day.getDayDate().isBefore(compareDay)){
                day.setStatus(1);
            } else {
                day.setStatus(0);
            }
            return day;
        }).collect(Collectors.toList());
        super.saveBatch(collect);
        return R.ok();
    }

    @Override
    public R updateListCourseData(List<FsUserCoursePeriodDays> entity) {
        List<FsUserCoursePeriodDays> collect = entity.stream().map(e -> {
            FsUserCoursePeriodDays day = new FsUserCoursePeriodDays();
            day.setId(e.getId());
            day.setMoney(e.getMoney());
            return day;
        }).collect(Collectors.toList());
        super.updateBatchById(collect);
        return R.ok();
    }

    @Override
    public List<CompanyRedPacketParam> getCompanyByPeriod(Long periodId, Long videoId) {
        if(videoId == null ){
            return fsUserCoursePeriodMapper.selectCompanyByPeriod(periodId);
        }
        return fsUserCoursePeriodMapper.selectCompanyByPeriodVideo(periodId, videoId);
    }

    @Override
    public List<PeriodRedPacketVO> getPeriodRedPacketList(Long periodId, Long companyId) {
        return fsUserCoursePeriodMapper.selectPeriodRedPacket(periodId, companyId);
    }

    @Override
    public List<FsPeriodCountVO> periodCourseCount(PeriodCountParam param) {
        //1、查询课程视频信息
        FsUserCoursePeriodDays fsUserCoursePeriodDays = new FsUserCoursePeriodDays();
        fsUserCoursePeriodDays.setPeriodId(param.getPeriodId());
        fsUserCoursePeriodDays.setVideoIds(param.getVideoIdList());
        fsUserCoursePeriodDays.setMaxDate(param.getMaxDate());

        List<FsUserCoursePeriodDays> videoList = baseMapper.selectFsUserCoursePeriodDaysList(fsUserCoursePeriodDays);

        //2、查询统计
        CourseAnalysisParam courseAnalysisParam = new CourseAnalysisParam();
        courseAnalysisParam.setPeriodId(param.getPeriodId());
        courseAnalysisParam.setVideoIdList(param.getVideoIdList());
        courseAnalysisParam.setCompanyId(param.getCompanyId());
        List<FsCourseAnalysisCountVO> courseCountList = fsUserMapper.courseAnalysisWatchLog(courseAnalysisParam);
        List<FsCourseAnalysisCountVO> redPacketCountList = fsUserMapper.courseAnalysisRedPacketCount(courseAnalysisParam);
        List<FsCourseAnalysisCountVO> answerCountList = fsUserMapper.courseAnalysisAnswerCount(courseAnalysisParam);

        //3、转化为map
        Map<Long, FsCourseAnalysisCountVO> courseMap = courseCountList.stream()
                .collect(Collectors.toMap(
                        FsCourseAnalysisCountVO::getVideoId,
                        Function.identity()
                ));
        Map<Long, FsCourseAnalysisCountVO> redPacketMap = redPacketCountList.stream()
                .collect(Collectors.toMap(
                        FsCourseAnalysisCountVO::getVideoId,
                        Function.identity()
                ));
        Map<Long, FsCourseAnalysisCountVO> answerMap = answerCountList.stream()
                .collect(Collectors.toMap(
                        FsCourseAnalysisCountVO::getVideoId,
                        Function.identity()
                ));

        //4、处理数据
        return videoList.stream().map(v -> {
            FsPeriodCountVO allVO = new FsPeriodCountVO();
            BeanUtils.copyProperties(v, allVO);
            allVO.setTitle(v.getVideoName());

            FsCourseAnalysisCountVO countVO = getCourseAnalysisCountVO(v, courseMap, redPacketMap, answerMap);
            allVO.setCountDetailsVO(countVO);
            return allVO;
        }).collect(Collectors.toList());
    }

    @Override
    public R periodCourseMove(Long id, Long targetId) {
        // 参数校验
        if (id == null || targetId == null || id.equals(targetId)) {
            return R.error(400, "参数不合法");
        }

        // 批量查询数据
        List<Long> idList = Arrays.asList(id, targetId);
        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = baseMapper.selectBatchIds(idList);

        // 数据校验
        if (fsUserCoursePeriodDays.size() != 2) {
            return R.error(404, "当前数据或移动的目标数据不存在");
        }

        // 获取源数据和目标数据
        FsUserCoursePeriodDays source = fsUserCoursePeriodDays.get(0);
        FsUserCoursePeriodDays target = fsUserCoursePeriodDays.get(1);

        // 交换数据
        swapPeriodDaysData(source, target);

        // 批量更新
        try {
            fsUserCoursePeriodDaysMapper.batchUpdateCoursePeriodDays(Arrays.asList(source, target));
            return R.ok();
        } catch (RuntimeException e) {
            log.error("上移/下移异常，当前id：{}，目标id：{}", id, targetId, e);
            return R.error(500, "操作失败，请稍后重试");
        }
    }

    /**
     * 交换两个课程时间段的数据
     */
    private void swapPeriodDaysData(FsUserCoursePeriodDays source, FsUserCoursePeriodDays target) {
        // 保存源数据
        LocalDate tempDayDate = source.getDayDate();
        Integer tempLesson = source.getLesson();
        LocalDateTime tempStartDateTime = source.getStartDateTime();
        LocalDateTime tempEndDateTime = source.getEndDateTime();
        LocalDateTime tempLastJoinTime = source.getLastJoinTime();

        // 将目标数据赋给源
        source.setDayDate(target.getDayDate());
        source.setLesson(target.getLesson());
        source.setStartDateTime(target.getStartDateTime());
        source.setEndDateTime(target.getEndDateTime());
        source.setLastJoinTime(target.getLastJoinTime());

        // 将保存的源数据赋给目标
        target.setDayDate(tempDayDate);
        target.setLesson(tempLesson);
        target.setStartDateTime(tempStartDateTime);
        target.setEndDateTime(tempEndDateTime);
        target.setLastJoinTime(tempLastJoinTime);
    }

    @Override
    public R updateCourseTime(UpdateCourseTimeVo vo) {
        // 批量更新
        if(vo.getBatchUpdateSwitch()!=null && vo.getBatchUpdateSwitch()==1
                && vo.getIds()!=null && vo.getIds().size()==1){
            Long id=vo.getIds().get(0);

            FsUserCoursePeriodDays info= fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysById(id);

            if(info==null || info.getPeriodId()==null || info.getLesson()==null){
                return R.error(400, "该课程参数异常，请联系管理员");
            }
            // 根据id获取当前营期的所有的大于该id数据lesson的id
            FsUserCoursePeriodDays param = new FsUserCoursePeriodDays();
            param.setPeriodId(info.getPeriodId());
            param.setLesson(info.getLesson());
            List<Long> ids = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysForLastById(param);
            List<FsUserCoursePeriodDays> list = fsUserCoursePeriodDaysMapper.selectBatchIds(ids);
            list.forEach(day -> {

                // 调整时间为直接接收前端传入的年月日，不使用营期的日期（2025年6月11日 10点41分）
                day.setStartDateTime(vo.getStartTime());
                day.setEndDateTime(vo.getEndTime1());


                SysConfig config = sysConfigMapper.selectConfigByConfigKey("joinTime.switch.config");
                if (ObjectUtils.isNotEmpty(config)&&config.getConfigValue().equals("1")){
                    day.setLastJoinTime(vo.getEndTime1());
                }else {
                    day.setLastJoinTime(vo.getJoinTime());
                }

                // 把营期时间改成开始时间
                day.setDayDate(vo.getStartTime().toLocalDate());
                // 设置状态
                LocalDateTime compareDayTime = LocalDateTime.now();
                if(compareDayTime.isAfter(day.getStartDateTime()) && compareDayTime.isBefore(day.getEndDateTime())){
                    day.setStatus(1);
                } else if(compareDayTime.isBefore(day.getStartDateTime())){
                    day.setStatus(0);
                } else {
                    day.setStatus(2);
                }
                fsUserCoursePeriodDaysMapper.updateById(day);

                // 时间加一天
                vo.setStartTime(vo.getStartTime().plusDays(1));
                vo.setEndTime1(vo.getEndTime1().plusDays(1));
                vo.setJoinTime(vo.getJoinTime().plusDays(1));
            });

        }else {
            List<FsUserCoursePeriodDays> list = fsUserCoursePeriodDaysMapper.selectBatchIds(vo.getIds());
            list.forEach(day -> {
//            day.setStartDateTime(LocalDateTime.of(day.getDayDate(), vo.getStartTime()));
//            day.setEndDateTime(LocalDateTime.of(day.getDayDate(), vo.getEndTime1()));
//            day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), vo.getJoinTime()));
                // 调整时间为直接接收前端传入的年月日，不使用营期的日期（2025年6月11日 10点41分）
                day.setStartDateTime(vo.getStartTime());
                day.setEndDateTime(vo.getEndTime1());

                SysConfig config = sysConfigMapper.selectConfigByConfigKey("joinTime.switch.config");
                if (ObjectUtils.isNotEmpty(config)&&config.getConfigValue().equals("1")){
                    day.setLastJoinTime(vo.getEndTime1());
                }else {
                    day.setLastJoinTime(vo.getJoinTime());
                }

                // 把营期时间改成开始时间
                day.setDayDate(vo.getStartTime().toLocalDate());
                // 设置状态
                LocalDateTime compareDayTime = LocalDateTime.now();
                if(compareDayTime.isAfter(day.getStartDateTime()) && compareDayTime.isBefore(day.getEndDateTime())){
                    day.setStatus(1);
                } else if(compareDayTime.isBefore(day.getStartDateTime())){
                    day.setStatus(0);
                } else {
                    day.setStatus(2);
                }
                fsUserCoursePeriodDaysMapper.updateById(day);
            });
        }



        return R.ok();
    }

    @Override
    public R updateCourseDate(UpdateCourseTimeVo vo) {
        FsUserCoursePeriodDays day = getById(vo.getId());
        FsUserCoursePeriod period = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(day.getPeriodId());
        if(!DateUtil.isWithinRangeSafe(vo.getDayDate(), period.getPeriodStartingTime(), period.getPeriodEndTime())) return R.error("时间不在营期范围内");
        day.setDayDate(vo.getDayDate());
        day.setStartDateTime(LocalDateTime.of(day.getDayDate(), day.getStartDateTime().toLocalTime()));
        day.setEndDateTime(LocalDateTime.of(day.getDayDate(), day.getEndDateTime().toLocalTime()));
        day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), day.getLastJoinTime().toLocalTime()));
        // 默认开启今天及以后的两天，为进行中
        LocalDate compareDay = LocalDate.now().plusDays(1);
        if(day.getDayDate().isBefore(compareDay)){
            day.setStatus(1);
        } else {
            day.setStatus(0);
        }
        updateById(day);
        return R.ok();
    }

    /**
     * 更新营期课程状态
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void changePeriodCourseStatus() {
        // 开启
        fsUserCoursePeriodDaysMapper.startPeriodCourse(LocalDateTime.now());

        // 关闭
        fsUserCoursePeriodDaysMapper.endPeriodCourse(LocalDateTime.now());
    }

    @Override
    public long periodCourseByCount(PeriodCountParam param) {
        //1、查询课程视频信息
        FsUserCoursePeriodDays fsUserCoursePeriodDays = new FsUserCoursePeriodDays();
        fsUserCoursePeriodDays.setPeriodId(param.getPeriodId());
        fsUserCoursePeriodDays.setVideoIds(param.getVideoIdList());
        fsUserCoursePeriodDays.setMaxDate(param.getMaxDate());

        return baseMapper.selectFsUserCoursePeriodDaysCount(fsUserCoursePeriodDays);
    }

    @Override
    public List<Long> selectFsUserCoursePeriodDaysByTime(String periodSTime, String periodETime) {
        return fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysByTime(periodSTime,periodETime);
    }

    @Override
    public List<FsUserCoursePeriodDays> selectFsUserCoursePeriodDaysByCourseId(Long courseId) {
        return fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysByCourseId(courseId);
    }

    private static FsCourseAnalysisCountVO getCourseAnalysisCountVO(FsUserCoursePeriodDays v, Map<Long, FsCourseAnalysisCountVO> courseMap, Map<Long, FsCourseAnalysisCountVO> redPacketMap, Map<Long, FsCourseAnalysisCountVO> answerMap) {
        FsCourseAnalysisCountVO countVO = new FsCourseAnalysisCountVO();
        FsCourseAnalysisCountVO courseVO = courseMap.getOrDefault(v.getVideoId(), countVO);
        FsCourseAnalysisCountVO redPacketVO = redPacketMap.getOrDefault(v.getVideoId(), countVO);
        FsCourseAnalysisCountVO answerVO = answerMap.getOrDefault(v.getVideoId(), countVO);
        //单独赋值
        countVO.setVideoId(v.getVideoId()).setCourseWatchNum(courseVO.getCourseWatchNum()).setCourseCompleteNum(courseVO.getCourseCompleteNum())
                .setCompleteRate(courseVO.getCompleteRate() != null ? courseVO.getCompleteRate() : new BigDecimal(BigInteger.ZERO))
                .setCourseWatchTimes(courseVO.getCourseWatchTimes()).setCourseCompleteTimes(courseVO.getCourseCompleteTimes());
        countVO.setRedPacketNum(redPacketVO.getRedPacketNum())
                .setRedPacketAmount(redPacketVO.getRedPacketAmount() != null ? redPacketVO.getRedPacketAmount() : new BigDecimal(BigInteger.ZERO));
        countVO.setAnswerNum(answerVO.getAnswerNum()).setAnswerRightNum(answerVO.getAnswerRightNum())
                .setAnswerRightRate(answerVO.getAnswerRightRate()!=null ? answerVO.getAnswerRightRate() : new BigDecimal(BigInteger.ZERO))
                .setAnswerTimes(answerVO.getAnswerTimes()).setAnswerRightTimes(answerVO.getAnswerRightTimes());
        return countVO;
    }

    /**
     * 查询营期选项列表
     * @param params    参数
     * @return  list
     */
    @Override
    public List<OptionsVO> selectPeriodListByMap(Map<String, Object> params) {
        return baseMapper.selectPeriodListByMap(params);
    }
}
