package cn.reghao.oss.store.task.processor;

import cn.reghao.oss.store.db.repository.AudioRepository;
import cn.reghao.oss.store.model.po.AudioFile;
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.jutil.jdk.security.DigestUtil;
import cn.reghao.jutil.media.FFmpegWrapper;
import cn.reghao.jutil.media.model.AudioProps;
import cn.reghao.jutil.media.model.MediaProps;
import cn.reghao.oss.api.constant.SupportedMedia;
import cn.reghao.oss.api.rest.UploadFileRet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author reghao
 * @date 2023-07-05 09:12:17
 */
@Slf4j
@Service
public class AudioFileProcessor {
    private final AudioRepository audioRepository;
    private final PutObjectService putObjectService;
    private final ObjectNameService objectNameService;
    private final FileStoreService fileStoreService;

    public AudioFileProcessor(AudioRepository audioRepository, PutObjectService putObjectService,
                              ObjectNameService objectNameService, FileStoreService fileStoreService) {
        this.audioRepository = audioRepository;
        this.putObjectService = putObjectService;
        this.objectNameService = objectNameService;
        this.fileStoreService = fileStoreService;
    }

    public UploadFileRet process(ObjectResult objectResult) throws Exception {
        String objectName = objectResult.getObjectName();
        String objectId = objectResult.getObjectId();
        String audioFileId = objectId;
        String objectUrl = objectNameService.getObjectUrl(objectName);
        boolean duplicate = objectResult.isDuplicate();
        if (duplicate) {
            String dupObjectId = objectResult.getDupObjectId();
            List<AudioFile> audioFiles = audioRepository.findAudioFiles(dupObjectId);
            AudioFile audioFile = audioFiles.get(0);
            AudioFile audioFile1 = new AudioFile(audioFileId, objectId, objectUrl, audioFile);
            List<AudioFile> list = new ArrayList<>();
            list.add(audioFile1);

            if (audioFiles.size() > 1) {
                for (int i = 1; i < audioFiles.size(); i++) {
                    AudioFile audioFile2 = audioFiles.get(i);
                    ObjectResult objectResult1 = putObjectService.copyFromObjectId(audioFile2.getObjectId());
                    String objectId1 = objectResult1.getObjectId();
                    String objectUrl1 = objectNameService.getObjectUrl(objectResult1.getObjectName());
                    list.add(new AudioFile(audioFileId, objectId1, objectUrl1, audioFile2));
                }
            }

            audioRepository.saveAudioFiles(list);
            return new UploadFileRet(objectId, null);
        }

        String absolutePath = objectResult.getAbsolutePath();
        MediaProps mediaProps = FFmpegWrapper.getMediaProps(absolutePath);
        if (mediaProps == null || mediaProps.getAudioProps() == null) {
            String errMsg = String.format("%s 的 FFmpeg 音频信息为 null", objectName);
            throw new Exception(errMsg);
        }

        AudioProps audioProps = mediaProps.getAudioProps();
        String audioCodec = audioProps.getCodecName();
        int duration = audioProps.getDuration().intValue();
        long bitRate = audioProps.getBitRate();

        List<AudioFile> list = new ArrayList<>();
        AudioFile audioFile = new AudioFile(audioFileId, objectId, duration, audioCodec, bitRate, objectUrl);
        list.add(audioFile);

        if (!SupportedMedia.audioCodecs.contains(audioCodec)) {
            File file = new File(objectResult.getAbsolutePath());
            AudioFile audioFile1 = getConvertedAudioFile(audioFileId, file, objectName, ".m4a");
            if (audioFile1 != null) {
                list.add(audioFile1);
            } else {
                log.error("{} 对象转换为 aac 编码失败", objectName);
            }
        }

        audioRepository.saveAudioFiles(list);
        return new UploadFileRet(audioFileId, null);
    }

    private AudioFile getConvertedAudioFile(String audioFileId, File file, String originalObjectName, String suffix) {
        String contentId = UUID.randomUUID().toString().replace("-", "");
        String destPath = fileStoreService.genFilePath(contentId, file.length(), suffix);
        try {
            File savedFile = new File(destPath);
            if (savedFile.exists()) {
                throw new IOException(destPath + " exist");
            }

            int ret = FFmpegWrapper.convertAudio(file.getAbsolutePath(), destPath);
            if (ret != 0) {
                throw new Exception("音频转码失败");
            }
            String sha256sum = DigestUtil.sha256sum(destPath);
            MediaProps mediaProps = FFmpegWrapper.getMediaProps(destPath);
            if (mediaProps == null || mediaProps.getAudioProps() == null) {
                log.error("转码后的 {} 文件 FFmpeg 音频信息为 null", destPath);
                throw new Exception("音频编码信息获取失败");
            }

            AudioProps audioProps = mediaProps.getAudioProps();
            String audioCodec = audioProps.getCodecName();
            int duration = audioProps.getDuration().intValue();
            long bitRate = audioProps.getBitRate();

            ObjectProp objectProp = objectNameService.getObjectProp(originalObjectName, suffix);
            String originalFilename = "";
            ObjectResult objectResult = putObjectService.putObject(objectProp, contentId, savedFile, originalFilename, sha256sum);
            String objectId = objectResult.getObjectId();
            String url = objectNameService.getObjectUrl(objectResult.getObjectName());
            String codec = "aac";
            return new AudioFile(audioFileId, objectId, duration, codec, bitRate, url);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}
