package com.fs.course.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.fs.common.core.domain.R;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import com.fs.common.utils.bean.BeanUtils;
import com.fs.course.domain.FsUserCourseVideo;
import com.fs.course.dto.VideoFavoriteStatusDTO;
import com.fs.course.dto.VideoLikeStatusDTO;
import com.fs.course.mapper.*;
import com.fs.course.param.*;
import com.fs.course.service.IRecommendationService;
import com.fs.course.vo.FsUserVideoListPVO;
import com.fs.course.vo.FsUserVideoPVO;
import com.fs.course.param.FsUserVideoParam;
import com.fs.course.vo.FsUserVideoListUVO;

import com.volcengine.helper.VodUploadProgressListener;
import com.volcengine.model.beans.Functions;
import com.volcengine.service.vod.IVodService;
import com.volcengine.service.vod.model.request.VodGetMediaInfosRequest;
import com.volcengine.service.vod.model.request.VodUploadMediaRequest;
import com.volcengine.service.vod.model.response.VodCommitUploadInfoResponse;
import com.volcengine.service.vod.model.response.VodGetMediaInfosResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.fs.course.domain.FsUserVideo;
import com.fs.course.service.IFsUserVideoService;
import org.springframework.web.multipart.MultipartFile;

/**
 * 课堂视频Service业务层处理
 *
 * @author fs
 * @date 2024-05-15
 */
@Slf4j
@Service
public class FsUserVideoServiceImpl implements IFsUserVideoService {
    @Autowired
    private FsUserVideoMapper fsUserVideoMapper;
    @Autowired
    private FsUserVideoLikeMapper fsUserVideoLikeMapper;
    @Autowired
    private FsUserVideoFavoriteMapper fsUserVideoFavoriteMapper;
    @Autowired
    private FsUserVideoCommentMapper fsUserVideoCommentMapper;
    @Autowired
    private FsUserTalentFollowMapper fsUserTalentFollowMapper;
    @Autowired
    private IRecommendationService recommendationService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IVodService vodService;
    private static final String LIKE_KEY_PREFIX = "like:video:";
    private static final String FAVORITE_KEY_PREFIX = "favorite:video:";

    /**
     * 查询课堂视频
     *
     * @param videoId 课堂视频主键
     * @return 课堂视频
     */
    @Override
    public FsUserVideo selectFsUserVideoByVideoId(String videoId) {
        return fsUserVideoMapper.selectFsUserVideoByVideoId(videoId);
    }

    /**
     * 查询课堂视频列表
     *
     * @param fsUserVideo 课堂视频
     * @return 课堂视频
     */
    @Override
    public List<FsUserVideo> selectFsUserVideoList(FsUserVideo fsUserVideo) {
        return fsUserVideoMapper.selectFsUserVideoList(fsUserVideo);
    }

    /**
     * 新增课堂视频
     *
     * @param fsUserVideo 课堂视频
     * @return 结果
     */
    @Override
    public int insertFsUserVideo(FsUserVideo fsUserVideo) {
        fsUserVideo.setCreateTime(DateUtils.getNowDate());
        return fsUserVideoMapper.insertFsUserVideo(fsUserVideo);
    }

    /**
     * 修改课堂视频
     *
     * @param fsUserVideo 课堂视频
     * @return 结果
     */
    @Override
    public int updateFsUserVideo(FsUserVideo fsUserVideo) {
        fsUserVideo.setUpdateTime(DateUtils.getNowDate());
        return fsUserVideoMapper.updateFsUserVideo(fsUserVideo);
    }

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

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

    @Override
    public List<FsUserVideo> selectFsUserVideoListByCourseId(FsUserVideo fsUserVideo) {
        return fsUserVideoMapper.selectFsUserVideoListByCourseId(fsUserVideo);
    }

    @Override
    public R addUserVideo(FsUserVideoAddParam param) {
        FsUserVideo fsUserVideo = new FsUserVideo();
        BeanUtils.copyProperties(param, fsUserVideo);
        fsUserVideo.setCreateTime(DateUtils.getNowDate());
        fsUserVideo.setIsAudit(0);
        fsUserVideo.setSource(1);
        fsUserVideo.setStatus(1);
//        fsUserVideo.setComments(0L);
        fsUserVideoMapper.insertFsUserVideo(fsUserVideo);
        return R.ok();
    }

    @Override
    public List<FsUserVideoListPVO> selectFsUserVideoListPVO(FsUserVideoParam param) {
        return fsUserVideoMapper.selectFsUserVideoListPVO(param);
    }

    @Override
    public int updateLikes(Long videoId, Integer type) {
        if (type == 1) {
            return fsUserVideoMapper.addLikes(videoId);
        } else {
            return fsUserVideoMapper.minusLikes(videoId);
        }
    }


    @Override
    public int updateFavorite(Long videoId, Integer type) {
        if (type == 1) {
            return fsUserVideoMapper.addFavorite(videoId);
        } else {
            return fsUserVideoMapper.minusFavorite(videoId);
        }
    }


    @Override
    public List<FsUserVideoListUVO> selectFsUserVideoListUVO(FsUserVideoListUParam param) {
        List<FsUserVideoListUVO> list = fsUserVideoMapper.selectFsUserVideoListUVO(param);

        if (param != null && param.getUserId() != null) {
            Long userId = param.getUserId();
            list = selectLikesAndFavorites(userId, list);
        }
        return list;
    }


    @Override
    public List<FsUserVideoListUVO> selectFsUserFavoriteVideoListUVO(FsUserVideoFavoriteListUParam param) {
        List<FsUserVideoListUVO> list = new ArrayList<>();
        if (param.getType() == 1) {
            list = fsUserVideoMapper.selectFsUserLikeVideoListUVO(param.getUserId());
        } else if (param.getType() == 2) {
            list = fsUserVideoMapper.selectFsUserFavoriteVideoListUVO(param.getUserId());
        } else {
            list = fsUserVideoMapper.selectFsUserCommentVideoListUVO(param.getUserId());
        }
        list = selectLikesAndFavorites(param.getUserId(), list);
        return list;
    }

    //查询点赞信息和收藏信息
    public List<FsUserVideoListUVO> selectLikesAndFavorites(Long userId, List<FsUserVideoListUVO> list) {
        if (list != null && !list.isEmpty()) {
            List<Long> videoIds = list.stream().map(vo -> Long.parseLong(vo.getId())).collect(Collectors.toList());

            List<String> likeKeys = videoIds.stream()
                    .map(videoId -> LIKE_KEY_PREFIX + videoId + ":user:" + userId)
                    .collect(Collectors.toList());
            List<Boolean> redisLikes = redisTemplate.opsForValue().multiGet(likeKeys);

            List<String> favoriteKeys = videoIds.stream()
                    .map(videoId -> FAVORITE_KEY_PREFIX + videoId + ":user:" + userId)
                    .collect(Collectors.toList());
            List<Boolean> redisFavorites = redisTemplate.opsForValue().multiGet(favoriteKeys);

            List<Long> missingLikeVideoIds = new ArrayList<>();
            List<Long> missingFavoriteVideoIds = new ArrayList<>();

            for (int i = 0; i < list.size(); i++) {
                FsUserVideoListUVO vo = list.get(i);
                Long videoId = Long.parseLong(vo.getId());
                Integer commentCount = fsUserVideoCommentMapper.selectCommentCountByVideos(videoId);
                vo.setSmsNum(commentCount);
                if (redisLikes != null && redisLikes.get(i) != null) {
                    vo.setLike(Boolean.TRUE.equals(redisLikes.get(i)) ? 1 : 0);
                } else {
                    missingLikeVideoIds.add(videoId);
                }

                if (redisFavorites != null && redisFavorites.get(i) != null) {
                    vo.setFavorite(Boolean.TRUE.equals(redisFavorites.get(i)) ? 1 : 0);
                } else {
                    missingFavoriteVideoIds.add(videoId);
                }
            }

            if (!missingLikeVideoIds.isEmpty()) {
                Map<Long, VideoLikeStatusDTO> likeMap = fsUserVideoLikeMapper.checkLikes(missingLikeVideoIds, userId);
                for (FsUserVideoListUVO vo : list) {
                    Long videoId = Long.parseLong(vo.getId());
                    if (missingLikeVideoIds.contains(videoId)) {
                        vo.setLike(likeMap.getOrDefault(videoId, new VideoLikeStatusDTO()).getLiked() ? 1 : 0);
                    }
                }
            }

            if (!missingFavoriteVideoIds.isEmpty()) {
                Map<Long, VideoFavoriteStatusDTO> favoriteMap = fsUserVideoFavoriteMapper.checkFavorites(missingFavoriteVideoIds, userId);
                for (FsUserVideoListUVO vo : list) {
                    Long videoId = Long.parseLong(vo.getId());
                    if (missingFavoriteVideoIds.contains(videoId)) {
                        vo.setFavorite(favoriteMap.getOrDefault(videoId, new VideoFavoriteStatusDTO()).getFavorite() ? 1 : 0);
                    }
                }
            }

            fillTalentFollowInfo(userId, list);
        }
        return list;
    }

    private void fillTalentFollowInfo(Long userId, List<FsUserVideoListUVO> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        List<Long> talentIds = list.stream()
                .map(FsUserVideoListUVO::getTalentId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        Set<Long> followedTalentIds = Collections.emptySet();
        if (userId != null && !talentIds.isEmpty()) {
            followedTalentIds = new HashSet<>(fsUserTalentFollowMapper.selectFollowedTalentIds(talentIds, userId));
        }
        for (FsUserVideoListUVO vo : list) {
            if (vo.getTalentId() != null && followedTalentIds.contains(vo.getTalentId())) {
                vo.setIsFollow(1);
            } else {
                vo.setIsFollow(0);
            }
        }
    }

    @Override
    public FsUserVideoPVO selectFsUserVideoPVOByVideoId(Long videoId) {
        return fsUserVideoMapper.selectFsUserVideoPVO(videoId);
    }

    @Override
    public int updateShares(Long videoId) {
        return fsUserVideoMapper.updateShares(videoId);
    }

    @Override
    public FsUserVideoListUVO getVideoById(Long videoId) {
        return getVideoById(videoId, null);
    }

    @Override
    public FsUserVideoListUVO getVideoById(Long videoId, Long userId) {
        FsUserVideoListUVO video = fsUserVideoMapper.selectFsUserVideoListUVOByVideoId(videoId);
        if (video != null && userId != null) {
            selectLikesAndFavorites(userId, Collections.singletonList(video));
        }
        return video;
    }

    @Override
    public int auditUserVideos(FsUserVideoAuditParam param) {
        return fsUserVideoMapper.auditUserVideos(param);
    }

    @Override
    public int updateFsUserVideoIsShow(Long[] videoIds, int i) {
        return fsUserVideoMapper.updateFsUserVideoIsShow(videoIds, i);
    }

    @Autowired
    private FsUserCourseVideoMapper courseVideoMapper;

    @Override
    public void updateVideoUrl() {
        List<FsUserCourseVideo> videos = courseVideoMapper.selectVideoIsPrivate();
        for (FsUserCourseVideo video : videos) {
            String url = updateUrlPrefix(video.getLineTwo());
            FsUserCourseVideo video1 = new FsUserCourseVideo();
            video1.setLineTwo(url);
            video1.setVideoId(video.getVideoId());
            courseVideoMapper.updateFsUserCourseVideo(video1);
        }
    }

    @Override
    public List<FsUserVideoListUVO> addNum(List<FsUserVideoListUVO> oldList) {
        if (oldList != null && !oldList.isEmpty()) {
            //随机添加点赞,收藏,分享数量
            for (FsUserVideoListUVO vo : oldList) {
                int likeAddNum = 0;
                int favoriteAddNum = 0;
                int sharesAddNum = 0;
                String addNum = vo.getAddNum();
                if (StringUtils.isBlank(addNum)) {
                    FsUserVideo video = fsUserVideoMapper.selectFsUserVideoByVideoId(vo.getId());
                    if (video != null && StringUtils.isNotBlank(video.getAddNum())) {
                        addNum = video.getAddNum();
                        vo.setAddNum(addNum);
                    }
                }
                Random random = new Random();
                if (StringUtils.isNotBlank(addNum)) {
                    List<String> addNums = Arrays.asList(addNum.split(","));
                    if (addNums.size() >= 3) {
                        likeAddNum = Integer.parseInt(addNums.get(0));
                        favoriteAddNum = Integer.parseInt(addNums.get(1));
                        sharesAddNum = Integer.parseInt(addNums.get(2));
                    } else {
                        // 生成1000到20000之间的随机整数
                        likeAddNum = 1000 + random.nextInt(20000 - 1000 + 1);
                        favoriteAddNum = 1000 + random.nextInt(likeAddNum - 1000 + 1);
                        sharesAddNum = 1000 + random.nextInt(favoriteAddNum - 1000 + 1);
                        FsUserVideo fsUserVideo = new FsUserVideo();
                        fsUserVideo.setVideoId(Long.valueOf(vo.getId()));
                        fsUserVideo.setAddNum(likeAddNum + "," + favoriteAddNum + "," + sharesAddNum);
                        updateFsUserVideo(fsUserVideo);
                    }
                } else {
                    // 生成1000到20000之间的随机整数
                    likeAddNum = 1000 + random.nextInt(20000 - 1000 + 1);
                    favoriteAddNum = 1000 + random.nextInt(likeAddNum - 1000 + 1);
                    sharesAddNum = 1000 + random.nextInt(favoriteAddNum - 1000 + 1);
                    FsUserVideo fsUserVideo = new FsUserVideo();
                    fsUserVideo.setVideoId(Long.valueOf(vo.getId()));
                    fsUserVideo.setAddNum(likeAddNum + "," + favoriteAddNum + "," + sharesAddNum);
                    updateFsUserVideo(fsUserVideo);
                }
                vo.setLikeNum((vo.getLikeNum() == null ? 0 : vo.getLikeNum()) + likeAddNum);
                vo.setFavoriteNum((vo.getFavoriteNum() == null ? 0 : vo.getFavoriteNum()) + favoriteAddNum);
                vo.setShares((vo.getShares() == null ? 0L : vo.getShares()) + sharesAddNum);

            }
        }
        return oldList;
    }

    @Override
    public List<FsUserVideo> selectVideoByTalentId(Long talentId) {
        return fsUserVideoMapper.selectVideoByTalentId(talentId);
    }

    @Override
    public int countFavoriteVideos(Long userId) {
        return fsUserVideoMapper.countFavoriteVideos(userId);
    }

    @Override
    public R addUserVideoByTalent(FsUserVideoAddParam param) {
        FsUserVideo fsUserVideo = new FsUserVideo();
        BeanUtils.copyProperties(param, fsUserVideo);
        fsUserVideo.setCreateTime(DateUtils.getNowDate());
        fsUserVideo.setIsAudit(0);
        fsUserVideo.setSource(2);
        fsUserVideo.setStatus(1);
        //fsUserVideo.setCateId(param.getCateId());
//        fsUserVideo.setComments(0L);
        fsUserVideoMapper.insertFsUserVideo(fsUserVideo);
        return R.ok();
    }

    @Override
    public List<FsUserVideoListUVO> selectFsUserVideoListUVOByUser(Long talentId, boolean oneSelf, Long userId) {
        List<FsUserVideoListUVO> list = fsUserVideoMapper.selectFsUserVideoListUVOByUser(talentId, oneSelf);
        if (userId != null && !list.isEmpty()) {
            list = selectLikesAndFavorites(userId, list);
        }
        return list;
    }

    /**
     * 删除达人视频信息
     *
     * @param videoId 课堂视频id
     * @param userId 用户id
     * @return 结果
     */
    @Override
    public R deleteFsUserVideoByVideoIdWithVerify(Long videoId, Long userId) {
        if (videoId == null) {
            return R.error("请选择要删除的视频");
        }
        FsUserVideoPVO entity = fsUserVideoMapper.selectFsUserVideoPVO(videoId);
        if (entity == null) {
            return R.error("视频不存在");
        } else if (!Objects.equals(entity.getUserId(), userId)) {
            return R.error("您没有权限删除此视频");
        }
        this.deleteFsUserVideoByVideoId(videoId.toString().trim());
        return R.ok();
    }

    @Override
    public R updateVideoStatusWithVerify(FsUserVideo fsUserVideo, Long userId) {
        if (fsUserVideo.getVideoId() == null) {
            return R.error("请选择要操作的视频");
        }
        FsUserVideoPVO entity = fsUserVideoMapper.selectFsUserVideoPVO(fsUserVideo.getVideoId());
        if (entity == null) {
            return R.error("视频不存在");
        } else if (!Objects.equals(entity.getUserId(), userId)) {
            return R.error("您没有权限操作此视频");
        }
        this.updateFsUserVideoIsShow(new Long[]{fsUserVideo.getVideoId()}, fsUserVideo.getStatus());
        return R.ok();
    }

    public static String updateUrlPrefix(String url) {
        final String oldPrefix = "https://obs.ylrztop.com";
        final String newPrefix = "https://rtobs.ylrztop.com";

        // 判断是否以 oldPrefix 开头，如果是，则进行替换
        if (url.startsWith(oldPrefix)) {
            // 去掉 oldPrefix 前缀，然后拼上 newPrefix
            return newPrefix + url.substring(oldPrefix.length());
        }
        // 如果不是以 oldPrefix 开头，则原样返回
        return url;
    }

    //本地文件视频上传
    @Override
    public String uploadVideo(MultipartFile file, String uploadId) {
        log.info("上传视频开始",uploadId);
        File tempFile = null;
        try {
            // 将 MultipartFile 转换为临时文件（固定 .tmp 后缀，禁止用户可控后缀落盘）
            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".mp4")) {
                throw new ServiceException("仅支持 MP4 视频格式");
            }
            tempFile = File.createTempFile("upload_", ".tmp");
            file.transferTo(tempFile);

            // 点播空间名称
            String space = "rt-huoshan";
            // 本地临时文件路径（用于上传）
            String localFilePath = tempFile.getAbsolutePath();

            // 火山云存储路径（文件上传后在火山云的路径）
            String datePath = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String fileName = System.currentTimeMillis() + ".mp4";
            String remoteFileName = "course/" + datePath + "/" + fileName;

            // 上传功能函数，可用于实现截图、设置媒资信息、触发工作流进行转码等功能。详见[上传功能函数说明](https://www.volcengine.com/docs/4/1185644)
            List<Functions> functionsList = new ArrayList<>();
            Functions getMetaFunc = Functions.GetMetaFunction();
            functionsList.add(getMetaFunc);
            Functions snapShotFunc = Functions.SnapShotFunction(2.3);
            functionsList.add(snapShotFunc);
            Functions addOptionInfo = Functions.AddOptionInfoFunction(fileName, "test", "用户上传视频", 0, true);
            functionsList.add(addOptionInfo);

            // 使用工作流进行转码

            List<String> impTemplateIds = new ArrayList<>();
//            impTemplateIds.add("a4a7066c968344e9bf7a56ec0891fbb8");
//            FunctionsWorkflowTemplate impTemplate = new FunctionsWorkflowTemplate(impTemplateIds, "imp");
//
//            List<String> transcodeTemplateIds = new ArrayList<>();
//            transcodeTemplateIds.add("a4a7066c968344e9bf7a56ec0891fbb8");
//            FunctionsWorkflowTemplate transcodeTemplate = new FunctionsWorkflowTemplate(transcodeTemplateIds,
//                    "transcode");

//            List<FunctionsWorkflowTemplate> templates = new ArrayList<>();
//            templates.add(impTemplate);
//            templates.add(transcodeTemplate);

//            Functions workflowFunc = Functions.StartWorkFlowFunction(templates);
//            functionsList.add(workflowFunc);

            VodUploadMediaRequest vodUploadMediaRequest = VodUploadMediaRequest.newBuilder()
                    .setSpaceName(space)
                    .setFilePath(localFilePath)  // 使用本地临时文件路径
                    .setFileName(remoteFileName)  // 火山云存储路径
                    .setFunctions(JSON.toJSONString(functionsList))
                    .setStorageClass(1)
                    .build();

            // 需要进度条功能时添加相应 listener，如无需求，传 null 值即可
            VodUploadProgressListener listener = new VodUploadMediaProcessListener(uploadId, redisTemplate);

            VodCommitUploadInfoResponse vodCommitUploadInfoResponse = vodService.uploadMedia(vodUploadMediaRequest, listener);

            redisTemplate.opsForValue()
                    .set("vod:upload:" + uploadId, 100, 10, TimeUnit.MINUTES);

            if (vodCommitUploadInfoResponse.getResponseMetadata().hasError()) {
                throw new RuntimeException("火山云上传失败: " + vodCommitUploadInfoResponse.getResponseMetadata().getError());
            }

            // 返回视频 VID
            String vid = vodCommitUploadInfoResponse.getResult().getData().getVid();
            System.out.println("视频上传成功，VID: " + vid);
            System.out.println("RequestId: " + vodCommitUploadInfoResponse.getResponseMetadata().getRequestId());

            return vid;
        } catch (Exception e) {
            throw new RuntimeException("视频上传失败: " + e.getMessage(), e);
        } finally {
            // 删除临时文件
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();
            }
        }
    }

    //根据vid查询视频信息
    @Override
    public String getVideoInfoByVid(String vid) {
        try {
            VodGetMediaInfosRequest.Builder reqBuilder = VodGetMediaInfosRequest.newBuilder();
            reqBuilder.setVids("vid");

            VodGetMediaInfosResponse resp = vodService.getMediaInfos20230701(reqBuilder.build());
            if (resp.getResponseMetadata().hasError()) {
                System.out.println(resp.getResponseMetadata().getError());
                System.exit(-1);
            }else {
                return resp.getResult().getMediaInfoList(0).getSourceInfo().getStoreUri();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
