package cn.reghao.tnb.content.app.vod.service.impl;

import cn.reghao.file.api.dto.ObjectMeta;
import cn.reghao.file.api.dto.VideoMeta;
import cn.reghao.file.api.iface.JobService;
import cn.reghao.file.api.iface.OssService;
import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.jutil.jdk.string.IdGenerator;
import cn.reghao.tnb.content.app.vod.model.dto.VideoUrlDto;
import cn.reghao.tnb.common.auth.UserContext;
import cn.reghao.tnb.content.api.constant.PostScope;
import cn.reghao.tnb.content.api.dto.VideoFilePublish;
import cn.reghao.tnb.content.api.dto.VideoFileUpdate;
import cn.reghao.tnb.content.api.dto.VideoPublishSbt;
import cn.reghao.tnb.content.app.vod.db.mapper.VideoPostMapper;
import cn.reghao.tnb.content.app.vod.db.repository.VideoRepository;
import cn.reghao.tnb.content.app.vod.model.dto.VideoCoverUpdate;
import cn.reghao.tnb.content.app.vod.model.dto.VideoInfoUpdate;
import cn.reghao.tnb.content.app.vod.model.dto.VideoScopeUpdate;
import cn.reghao.tnb.content.app.vod.model.po.VideoFile;
import cn.reghao.tnb.content.app.vod.model.po.VideoPost;
import cn.reghao.tnb.content.app.vod.model.po.VideoStatistic;
import cn.reghao.tnb.content.app.vod.service.CategoryService;
import cn.reghao.tnb.content.app.vod.service.TagService;
import cn.reghao.tnb.content.app.vod.service.VideoPostService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author reghao
 * @date 2024-08-06 20:55:49
 */
@Slf4j
@Service
public class VideoPostServiceImpl implements VideoPostService {
    @DubboReference(check = false, timeout = 60_000)
    private OssService ossService;
    @DubboReference(check = false)
    private JobService jobService;

    private final IdGenerator idGenerator;
    private final VideoPostMapper videoPostMapper;
    private final VideoRepository videoRepository;
    private final TagService tagService;
    private final CategoryService categoryService;

    public VideoPostServiceImpl(VideoPostMapper videoPostMapper, VideoRepository videoRepository,
                                TagService tagService, CategoryService categoryService) {
        this.idGenerator = new IdGenerator("video-id");
        this.videoPostMapper = videoPostMapper;
        this.videoRepository = videoRepository;
        this.tagService = tagService;
        this.categoryService = categoryService;
    }

    public String publishVideoFile(VideoFilePublish videoFilePublish) throws Exception {
        String title = videoFilePublish.getFilename();
        String videoFileId = videoFilePublish.getVideoFileId();
        int channelCode = videoFilePublish.getChannelCode();
        VideoMeta videoMeta = ossService.getVideoMeta(videoFileId);
        if (!videoMeta.getFormatName().contains("mov,mp4")) {
            //long jobId = jobService.addConvertVideoJob(videoFileId, channelCode);
                /*Result result1 = fileService.convertVideo(videoFileId, channelCode);
                if (result1.getCode() == ResultStatus.SUCCESS.getCode()) {
                    videoPost.setStatus(VideoStatus.converted.getCode());
                } else {
                    log.error(result1.getMsg());
                }*/
        }

        String videoId = idGenerator.getUuid();
        VideoFile videoFile = new VideoFile(videoId, videoMeta, channelCode);
        VideoPost videoPost = new VideoPost(videoId, title, videoFile);
        videoRepository.saveVideo(videoFile, videoPost);
        return videoId;
    }

    public Result publishVideoPost(VideoPublishSbt videoPublishSbt) {
        Result result;
        try {
            String coverFileId = videoPublishSbt.getCoverFileId();
            ObjectMeta objectMeta = ossService.getObjectMeta(coverFileId);
            if (objectMeta == null) {
                String errMsg = String.format("封面文件 %s 在 oss 中不存在", coverFileId);
                return Result.fail(errMsg);
            }
            String coverUrl = objectMeta.getUrl();

            String videoId = videoPublishSbt.getVideoId();
            VideoPost videoPost = videoRepository.getVideoPost(videoId);
            if (videoPost == null) {
                String errMsg = String.format("VideoId %s 不存在", videoId);
                return Result.fail(errMsg);
            }

            List<VideoFile> videoFileList = videoRepository.getVideoFiles(videoId);
            if (videoFileList.isEmpty()) {
                String errMsg = String.format("VideoId %s 关联的视频文件不存在", videoId);
                return Result.fail(errMsg);
            }
            VideoFile videoFile = videoFileList.get(0);
            String videoFileId = videoFile.getObjectId();

            int channelCode = videoFile.getChannelCode();
            int scope = videoPublishSbt.getScope();
            ossService.checkAndSetScope(videoFileId, scope);

            Set<String> tags = videoPublishSbt.getTags();
            String tags1 = tags.toString().replace("[", "").replace("]", "");

            Long scheduledTime = videoPublishSbt.getScheduledTime();
            if (scheduledTime == null) {
                long publishAt = System.currentTimeMillis();
                videoPost.update(videoPublishSbt, coverUrl, publishAt);
            } else {
                /*long duration = publishAt-System.currentTimeMillis();
                if (duration < 600_000) {
                    return Result.fail("定时发布的时间至少应在 10 分钟后");
                }*/
                videoPost.update(videoPublishSbt, coverUrl, scheduledTime);
            }

            saveVideoPublish(videoPost, tags1);
            if (scheduledTime != null) {
                long jobId = jobService.addPublishVideoJob(videoId, videoPublishSbt.getScheduledTime());
            }
            result = Result.success();
        } catch (Exception e) {
            result = Result.fail(e.getMessage());
        }

        return result;
    }

    public void saveVideoPublish(VideoPost videoPost, String tags) {
        String videoId = videoPost.getVideoId();
        videoRepository.updateVideoPublish(videoPost);
        tagService.addVideoTags(videoId, videoPost.getScope(), tags);
        categoryService.setVideoCategoryPost(videoPost);
    }

    @Transactional(rollbackFor = Exception.class)
    @Deprecated
    public void saveCrawledVideo(VideoPost videoPost, VideoStatistic videoStatistic, String tags) {
        videoRepository.saveVideoCrawled(videoPost, videoStatistic);
        String videoId = videoPost.getVideoId();
        tagService.addVideoTags(videoId, videoPost.getScope(), tags);
        categoryService.setVideoCategoryPost(videoPost);
    }

    public void updateVideoScope(VideoScopeUpdate videoScopeUpdate) {
        String videoId = videoScopeUpdate.getVideoId();
        VideoPost videoPost = videoRepository.getVideoPost(videoId);
        if (videoPost == null) {
            return;
        }

        List<VideoUrlDto> list = videoRepository.getVideoUrls(videoId);
        for (VideoUrlDto videoUrlDto : list) {
            String videoFileId = videoUrlDto.getObjectId();
            try {
                int scope = videoScopeUpdate.getScope();
                ossService.checkAndSetScope(videoFileId, scope);
                videoPostMapper.updateVideoScope(videoScopeUpdate);
            } catch (Exception e) {
                log.error("{}", e.getMessage());
            }
        }
    }

    public void updateVideoInfo(VideoInfoUpdate videoInfoUpdate) {
        String videoId = videoInfoUpdate.getVideoId();
        VideoPost videoPost = videoRepository.getVideoPost(videoId);
        if (videoPost == null) {
            return;
        }

        videoPostMapper.updateVideoInfo(videoInfoUpdate);
    }

    public void updateVideoCover(VideoCoverUpdate videoCoverUpdate) {
        String videoId = videoCoverUpdate.getVideoId();
        VideoPost videoPost = videoRepository.getVideoPost(videoId);
        if (videoPost == null) {
            return;
        }

        String coverFileId = videoCoverUpdate.getCoverFileId();
        try {
            ObjectMeta objectMeta = ossService.getObjectMeta(coverFileId);
            if (objectMeta == null) {
                return;
            }

            String coverUrl = objectMeta.getUrl();
            videoPostMapper.updateVideoCover(videoId, coverUrl);
            String currentCover = videoPost.getCoverUrl();
            deleteCoverFile(currentCover);
        } catch (Exception e) {
            log.error("{}", e.getMessage());;
        }
    }

    private void deleteCoverFile(String coverUrl) {
        try {
            ossService.deleteByObjectUrl(coverUrl);
        } catch (Exception e) {
            log.error("{}", e.getMessage());;
        }
    }

    public void updateVideoFile(VideoFileUpdate videoFileUpdate) {
        String videoId = videoFileUpdate.getVideoId();
        VideoPost videoPost = videoRepository.getVideoPost(videoId);
        if (videoPost == null) {
            return;
        }

        List<VideoUrlDto> list = videoRepository.getVideoUrls(videoId);
        for (VideoUrlDto videoUrlDto : list) {
            String videoFileId = videoFileUpdate.getVideoFileId();
            try {
                int channelCode = 101;
                VideoMeta videoMeta = ossService.getVideoMeta(videoFileId);
                if (videoMeta == null) {
                    log.error("{} not exist", videoFileId);
                    return;
                }

                videoPostMapper.updateVideoFile(videoId, videoMeta);
                int scope = videoPost.getScope();
                if (scope != PostScope.PRIVATE.getCode()) {
                    ossService.checkAndSetScope(videoId, scope);
                }

                ossService.deleteByObjectId(videoFileId);
            } catch (Exception e) {
                log.error("{}", e.getMessage());;
            }
        }
    }

    public void deleteVideo(String videoId) {
        VideoPost videoPost = videoRepository.getVideoPost(videoId);
        long owner = videoPost.getPublishBy();
        if (owner == UserContext.getUserId()) {
            // 删除 videoId 关联的所有数据, 包括观看记录, 用户收藏, 视频数据, 视频标签, 推荐数据等
            videoPostMapper.deleteByVideoId(videoId);

            String coverUrl = videoPost.getCoverUrl();
            deleteCoverFile(coverUrl);
            List<VideoUrlDto> list = videoRepository.getVideoUrls(videoId);
            for (VideoUrlDto videoUrlDto : list) {
                String videoFileId = videoUrlDto.getObjectId();
                try {
                    ossService.deleteByObjectId(videoFileId);
                } catch (Exception e) {
                    log.error("{}", e.getMessage());;
                }
            }
        }
    }
}
