package com.hc.business.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hc.business.dto.UserCourseDto;
import com.hc.business.mapper.CourseChapterVideoMapper;
import com.hc.business.mapper.UserCourseMapper;
import com.hc.business.mapper.UserVideoPositionMapper;
import com.hc.business.model.UserVideoPosition;
import com.hc.business.model.CourseChapterVideo;
import com.hc.business.model.UserCourse;
import com.hc.business.service.UserVideoPositionService;
import com.hc.core.utils.redis.RedisUtil;
import com.hc.core.utils.exception.ResponseException;
import com.hc.core.utils.tool.Compute;
import com.hc.core.utils.tool.Verification;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户视频观看记录(UserVideoPosition)表服务实现类
 *
 * @author java
 * @since 2020-05-29 15:50:50
 */

@Service("userVideoPositionService")
public class UserVideoPositionServiceImpl implements UserVideoPositionService {

    private final RedisUtil redisUtil;

    private final UserVideoPositionMapper userVideoPositionMapper;

    private final CourseChapterVideoMapper chapterVideoMapper;

    private final UserVideoPositionMapper positionMapper;

    private final UserCourseMapper userCourseMapper;

    private static final String REDIS_KEY_PREFIX = "user:video:position:";

    public UserVideoPositionServiceImpl(UserVideoPositionMapper userVideoPositionMapper, RedisUtil redisUtil, CourseChapterVideoMapper videoMapper,
                                        UserVideoPositionMapper positionMapper, UserCourseMapper userCourseMapper) {
        this.userVideoPositionMapper = userVideoPositionMapper;
        this.chapterVideoMapper = videoMapper;
        this.positionMapper = positionMapper;
        this.userCourseMapper = userCourseMapper;
        this.redisUtil = redisUtil;
    }

    /**
     * 通过ID查询单条数据
     *
     * @param userVideoPositionId 主键
     * @return 实例对象
     */
    @Override
    public UserVideoPosition queryById(Integer userVideoPositionId) {
        return userVideoPositionMapper.selectByPrimaryKey(userVideoPositionId);
    }

    /**
     * 新增数据
     *
     * @param userVideoPosition 实例对象
     * @return 实例对象
     */
    @Override
    public UserVideoPosition insert(UserVideoPosition userVideoPosition) {
        userVideoPositionMapper.insert(userVideoPosition);
        return userVideoPosition;
    }

    /**
     * 修改数据
     *
     * @param userVideoPosition 实例对象
     * @return 实例对象
     */
    @Override
    public UserVideoPosition update(UserVideoPosition userVideoPosition) {
        userVideoPositionMapper.updateByPrimaryKeySelective(userVideoPosition);
        return this.queryById(userVideoPosition.getUserVideoPositionId());
    }

    /**
     * 通过主键删除数据
     *
     * @param userVideoPositionId 主键
     * @return 是否成功
     */
    @Override
    public Boolean deleteById(Integer userVideoPositionId) {
        return userVideoPositionMapper.deleteByPrimaryKey(userVideoPositionId) > 0;
    }

    /**
     * 分页查询所有数据
     *
     * @return 实例对象数组
     */
    @Override
    public PageInfo queryAllByLimit(Integer page, Integer size) {
        PageHelper.startPage(page, size);
        List<UserVideoPosition> list = userVideoPositionMapper.selectAll();
        return new PageInfo(list);
    }

    /**
     * 重新计算课程的总进度，没有章节得概念，但是多个视频
     *
     * @param userId
     * @param years
     * @param courseId
     * @return
     */

    private boolean calcCourseChapterAndVideoPosition(Integer courseId, Integer userId, String years,Integer classId) {

        //重写计算
        //取一个课程所有的视频列表
        List<CourseChapterVideo> video_list = chapterVideoMapper.selectVideoByCourseId(courseId);
        if ((null == video_list) || (video_list.size() <= 0)) {
            return false;
        }

        //遍历每个视频的进度
        Double totalPercent = Double.valueOf("0");
        for (CourseChapterVideo video :
                video_list) {

            List<UserVideoPosition> position_list = positionMapper.selectUserPositionByUserAndVideo(video.getVideoId(), userId);
            if ((null == position_list) || (0 == position_list.size())) {
                continue;
            }

            try {
                Double videotime = Double.valueOf(position_list.get(0).getVideoTime());
                Double position = Double.valueOf(position_list.get(0).getVideoPosition());

                totalPercent = Compute.add(totalPercent, Compute.div(position, videotime, 2));
            } catch (Exception e) {
                //计算出错，不计入进度
                continue;
            }


        }

        //计算平均进度
        totalPercent = Compute.div(totalPercent, video_list.size(), 2);
        //如果章节进度有更新，需要从新计算课程总体进度，并更新到数据库
        //TODO 查询课程进度
        List<UserCourseDto> cardCourseList = userCourseMapper.selectUserCourseProgress(userId, classId,courseId);
        if (cardCourseList.size() > 0) {
            //课程进度有变化时 将查询的课程进度写入数据库
            if (!totalPercent.equals(cardCourseList.get(0).getCoursePercent())) {
                UserCourse userCourse = new UserCourse();
                BeanUtils.copyProperties(cardCourseList.get(0), userCourse);
                userCourse.setCoursePercent(totalPercent);
                userCourseMapper.updateByPrimaryKeySelective(userCourse);
            }
        } else {
            //如果没有课程得记录，则增加记录
            UserCourse userCourse = new UserCourse();
            userCourse.setCoursePercent(totalPercent);
            userCourse.setCourseId(courseId);
            userCourse.setUserId(userId);
            userCourse.setClassId(classId);
            userCourseMapper.insert(userCourse);
        }

        return true;
    }

    //课程进度接口
    //刷新进度到数据库
    @Override
    public int flushToDb(Integer userId, Integer videoId, Integer courseId, String years,Integer classId) {

        if ((null == videoId) || (null == userId) || (null == courseId)) {
            return 0;
        }
        String key = REDIS_KEY_PREFIX + userId + ":" + videoId;
        String key_v = "position" + String.valueOf(videoId);
        String key_t = "videotime" + String.valueOf(videoId);
        String key_u = "update" + String.valueOf(videoId);
        //没有缓存得进度信息，不刷新
        if ((true != redisUtil.hashHasKey(key, key_v)) || (true != redisUtil.hashHasKey(key, key_t))) {
            return 0;
        }

        /**
         * 首先更新单挑播放记录
         */

        String videoTime = redisUtil.hashGet(key, key_t).toString();
        String position = redisUtil.hashGet(key, key_v).toString();
        //首先查找是否存在userVideoPostion记录
        List<UserVideoPosition> plist = userVideoPositionMapper.selectUserPositionByUserAndVideo(videoId, userId);
        //不存在记录
        Double percent = Compute.div(Double.valueOf(position), Double.valueOf(videoTime), 2);

        if ((null == plist) || (plist.size() <= 0)) {
            //新增记录
            UserVideoPosition uposition = new UserVideoPosition();
            uposition.setVideoId(videoId);
            uposition.setUserId(userId);
            uposition.setVideoTime(videoTime);
            uposition.setVideoPosition(position);
            if (percent >= 0.95) {
                uposition.setWatchEnd(1);
            } else {
                uposition.setWatchEnd(0);
            }

            try {
                userVideoPositionMapper.insert(uposition);
            } catch (Exception e) {
                return 0;
            }
        } else {
            //修改记录,只保存一条记录
            UserVideoPosition uposition = plist.get(0);
            //位置比数据库保存得少，不刷新
            if (Double.valueOf(position) <= Double.valueOf(uposition.getVideoPosition())) {
                return 0;
            }
            uposition.setVideoPosition(position);
            if (percent >= 0.95) {
                uposition.setWatchEnd(1);
            } else {
                uposition.setWatchEnd(0);
            }
            try {
                userVideoPositionMapper.updateByPrimaryKey(uposition);
            } catch (Exception e) {
                return 0;
            }
        }

        //更新课程总进度
        calcCourseChapterAndVideoPosition(courseId, userId, years,classId);

        return 1;
    }

    @Override
    public Map<String, String> findVideoPosition(Integer userId, Integer videoId, Integer courseId,Integer classId) {

        String key = REDIS_KEY_PREFIX + userId + ":" + videoId ;
        String key_v = "position" + String.valueOf(videoId);
        String key_t = "videotime" + String.valueOf(videoId);
        String key_u = "update" + String.valueOf(videoId);

        //redis中不存在，从数据库查找，防止极端情况下，完全清理了缓存，全部丢掉数据
        Map<String, String> map = new HashMap<>(2);
        if ((true != redisUtil.hashHasKey(key, key_v)) || (true != redisUtil.hashHasKey(key, key_t))) {
            List<UserVideoPosition> position_list = userVideoPositionMapper.selectUserPositionByUserAndVideo(videoId, userId);
            if ((null != position_list) && (position_list.size() > 0)) {
                UserVideoPosition position = position_list.get(0);
                redisUtil.hashDel(key, key_t);
                redisUtil.hashDel(key, key_v);

                map.put("position", position.getVideoPosition());
                map.put("videotime", position.getVideoTime());

                redisUtil.hashSet(key, key_v, position.getVideoPosition());
                redisUtil.hashSet(key, key_v, position.getVideoTime());

                return map;
            }

        } else {
            String videoPosition = (null == redisUtil.hashGet(key, key_v)) ? null : redisUtil.hashGet(key, key_v).toString();
            String videoTime = (null == redisUtil.hashGet(key, key_t)) ? null : redisUtil.hashGet(key, key_t).toString();
            map.put("position", videoPosition);
            map.put("videotime", videoTime);
            if (redisUtil.hashHasKey(key, key_u)) {
                map.put("update", "1");
                redisUtil.hashDel(key, key_u);
            }
            return map;
        }

        return map;

    }

    @Override
    public UserVideoPosition getVideoPosition(Integer positionId) {
        return userVideoPositionMapper.selectByPrimaryKey(positionId);
    }

//    @Override
//    public int insertVideoPositionList(List<UserVideoPosition> userVideoPositionList) {
//        return userVideoPositionMapper.insertList(userVideoPositionList);
//    }


    @Override
    public UserVideoPosition insertPositionToRedis(UserVideoPosition userVideoPosition, Integer courseId) {

        String key = REDIS_KEY_PREFIX + userVideoPosition.getUserId() + ":" + userVideoPosition.getVideoId();
        String key_v = "position" + String.valueOf(userVideoPosition.getVideoId());
        String key_t = "videotime" + String.valueOf(userVideoPosition.getVideoId());
        //是否更新标记位,用来同步数据使用
        String key_u = "update" + String.valueOf(userVideoPosition.getVideoId());

        //校验播放记录百分比  大于97% 默认100%
        if (Verification.verificationString(userVideoPosition.getVideoTime()) && Verification.verificationString(userVideoPosition.getVideoPosition())) {
            if (Double.valueOf(userVideoPosition.getVideoPosition()) > Double.valueOf(userVideoPosition.getVideoTime())) {
                userVideoPosition.setVideoPosition(userVideoPosition.getVideoTime());
            }
            if (Double.valueOf(userVideoPosition.getVideoTime()) != 0) {
                Double percent = Compute.div(Double.valueOf(userVideoPosition.getVideoPosition()), Double.valueOf(userVideoPosition.getVideoTime()), 2);
                if (percent >= 0.95) {
                    //设置视频观看长度 = 视频总长
                    userVideoPosition.setVideoPosition(userVideoPosition.getVideoTime());
                }
            }
        }
        try {
            if (Verification.verificationString(userVideoPosition.getVideoPosition())) {
                if (redisUtil.hasKey(key)) {
                    //hashset已存在
                    String videoPosition = (String) redisUtil.hashGet(key, key_v);
                    String videoTime = (String) redisUtil.hashGet(key, key_t);

                    //表示i视频进度有更新
                    redisUtil.hashDel(key, key_u);
                    redisUtil.hashSet(key, key_u, "1");

                    //单个视频总长是否已存在
                    if (Verification.verificationString(videoTime)) {
                        //大于原先长
                        if (Double.valueOf(userVideoPosition.getVideoTime()) > Double.valueOf(videoTime)) {
                            redisUtil.hashDel(key, key_t);
                            redisUtil.hashSet(key, key_t, userVideoPosition.getVideoTime());
                        }
                    } else {
                        redisUtil.hashSet(key, key_t, userVideoPosition.getVideoTime());
                    }

                    //单个视频播放记录是否已存在
                    if (Verification.verificationString(videoPosition)) {
                        if (Double.valueOf(userVideoPosition.getVideoPosition()) > Double.valueOf(videoPosition)) {
                            //大于原先值
                            //先删除原先的存储
                            redisUtil.hashDel(key, key_v);
                            redisUtil.hashSet(key, key_v, userVideoPosition.getVideoPosition());
                        }

                        //如果位置大于视频最大长度，肯定出错了。不能超过视频最大长度
                        if (Double.valueOf(userVideoPosition.getVideoPosition()) >= Double.valueOf(videoTime)) {
                            redisUtil.hashDel(key, key_v);
                            redisUtil.hashSet(key, key_v, videoTime);
                        }
                    } else {
                        redisUtil.hashSet(key, key_v, userVideoPosition.getVideoPosition());
                    }
                } else {
                    //每次添加时将播放记录先添加至redis
                    Map<String, Object> pairs = new HashMap<String, Object>(16);
                    pairs.put(key_v, userVideoPosition.getVideoPosition());
                    pairs.put(key_t, userVideoPosition.getVideoTime());
                    pairs.put(key_u, "1");
                    redisUtil.hashMapSet(key, pairs);
                }
            }
            return userVideoPosition;
        } catch (Exception e) {
            throw new ResponseException(e.hashCode(), e.getMessage());
        }

    }
}