package cn.reghao.oss.store.task;

import cn.reghao.oss.store.db.repository.AudioRepository;
import cn.reghao.oss.store.db.repository.ObjectRepository;
import cn.reghao.oss.store.db.repository.VideoRepository;
import cn.reghao.oss.store.model.po.VideoFile;
import cn.reghao.oss.store.model.vo.ObjectProp;
import cn.reghao.oss.store.model.vo.ObjectResult;
import cn.reghao.oss.store.service.FileStoreService;
import cn.reghao.oss.store.service.ObjectNameService;
import cn.reghao.oss.store.service.PutObjectService;
import cn.reghao.oss.store.util.FileType;
import cn.reghao.oss.store.util.UserContext;
import cn.reghao.jutil.jdk.security.DigestUtil;
import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
import cn.reghao.jutil.media.FFmpegWrapper;
import cn.reghao.jutil.media.model.AudioProps;
import cn.reghao.jutil.media.model.MediaProps;
import cn.reghao.jutil.media.MediaQuality;
import cn.reghao.jutil.media.MediaResolution;
import cn.reghao.jutil.media.model.VideoProps;
import cn.reghao.oss.api.dto.ObjectMeta;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;

/**
 * @author reghao
 * @date 2023-10-08 13:46:28
 */
@Slf4j
@Service
public class MediaConverter {
    private final ExecutorService threadPool = ThreadPoolWrapper.threadPool("converter-pool", 10);
    private final ObjectRepository objectRepository;
    private final VideoRepository videoRepository;
    private final AudioRepository audioRepository;
    private final ObjectNameService objectNameService;
    private final FileStoreService fileStoreService;
    private final PutObjectService putObjectService;

    public MediaConverter(ObjectRepository objectRepository, VideoRepository videoRepository,
                          AudioRepository audioRepository, ObjectNameService objectNameService,
                          FileStoreService fileStoreService, PutObjectService putObjectService) {
        this.objectRepository = objectRepository;
        this.videoRepository = videoRepository;
        this.audioRepository = audioRepository;
        this.objectNameService = objectNameService;
        this.fileStoreService = fileStoreService;
        this.putObjectService = putObjectService;
    }

    public void convertVideo(String videoFileId) {
        threadPool.submit(new ConvertVideoTask(videoFileId));
    }

    public void convertAudio(String audioFileId) {
        threadPool.submit(new ConvertAudioTask(audioFileId));
    }

    class ConvertVideoTask implements Runnable {
        private final String videoFileId;

        public ConvertVideoTask(String videoFileId) {
            this.videoFileId = videoFileId;
        }

        public void run() {
            log.info("convert video file {}", videoFileId);
            VideoFile videoFile = videoRepository.getOriginalVideoFile(videoFileId);
            int width = videoFile.getWidth();
            int height = videoFile.getHeight();

            ObjectMeta objectMeta = objectRepository.getObjectMetaById(videoFileId);
            UserContext userContext = new UserContext(objectMeta.getUploadBy());
            String originalObjectName = objectMeta.getObjectName();
            String srcPath = objectMeta.getAbsolutePath();
            File srcFile = new File(srcPath);

            String contentId = UUID.randomUUID().toString().replace("-", "");
            String suffix = ".mp4";
            String destPath = fileStoreService.genFilePath(contentId, srcFile.length(), suffix);
            try {
                File savedFile = new File(destPath);
                if (savedFile.exists()) {
                    throw new IOException(destPath + " exist");
                }

                String format = suffix.replace(".", "");
                int ret = FFmpegWrapper.formatCovert(srcFile.getAbsolutePath(), destPath, format);
                if (ret != 0) {
                    throw new Exception("视频转码失败");
                }
                String sha256sum = DigestUtil.sha256sum(destPath);

                ObjectProp objectProp = objectNameService.getObjectProp(originalObjectName, suffix);
                String originalFilename = "converted_video";
                ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, originalFilename, sha256sum);

                String objectId = objectResult.getObjectId();
                String url = objectNameService.getObjectUrl(objectResult.getObjectName());
                String urlType = FileType.getVideoUrlType(destPath);

                MediaProps mediaProps = FFmpegWrapper.getMediaProps(destPath);
                if (mediaProps == null) {
                    log.error("{} 的 FFmpeg 媒体信息为 null", destPath);
                    return;
                }

                VideoProps videoProps = mediaProps.getVideoProps();
                if (videoProps == null) {
                    log.error("{} 的 FFmpeg 视频信息为 null", destPath);
                    return;
                }

                String videoCodec = videoProps.getCodecName();
                long vbitRate = videoProps.getBitRate();

                String audioCodec = null;
                long abitRate = 0;
                AudioProps audioProps1 = mediaProps.getAudioProps();
                if (audioProps1 != null) {
                    audioCodec = audioProps1.getCodecName();
                    abitRate = audioProps1.getBitRate();
                }

                int duration = videoFile.getDuration();
                MediaResolution mediaResolution = MediaQuality.getQuality(width, height);
                String quality = mediaResolution.getQualityStr();
                VideoFile videoFile1 = new VideoFile(videoFileId, objectId, videoCodec, vbitRate, audioCodec, abitRate,
                        urlType, url, quality, width, height, duration);
                videoRepository.saveVideoFiles(List.of(videoFile1));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class ConvertAudioTask implements Runnable {
        private final String audioFileId;

        public ConvertAudioTask(String audioFileId) {
            this.audioFileId = audioFileId;
        }

        @Override
        public void run() {
            log.info("convert audio file {}", audioFileId);
        }
    }
}
