package com.afanticar.aliyun.fc;

import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.afanticar.aliyun.fc.dto.response.AwemeCallbackContent;
import com.afanticar.aliyun.fc.dto.request.AwemeSimpleRequest;
import com.afanticar.aliyun.fc.util.FFmpegUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.Credentials;
import com.aliyun.fc.runtime.PojoRequestHandler;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.PutObjectResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * @Author: wuzhancai
 * @Desc: 视频音频 及 抽帧
 * @Date: 2023/6/2 13:51
 */
public class AwemeAudioFrameOss implements PojoRequestHandler<AwemeSimpleRequest, AwemeCallbackContent> {


    private static final Logger log = LoggerFactory.getLogger(AwemeAudioFrameOss.class);

    private static String ffmpegPath="/code/ffmpeg";

    static {
        try{
            String result = FFmpegUtil.assignmentFfmpegAuthority(ffmpegPath);
            log.info("result {}",result);
        }catch (Exception e){
            log.error("ffmpeg init fail {}",e);
        }
    }

    @Override
    public AwemeCallbackContent handleRequest(AwemeSimpleRequest request, Context context) {

        AwemeCallbackContent message = getAudio(request,context);
        return message;
    }

    public static void main(String[] args) {
        AwemeSimpleRequest request = new AwemeSimpleRequest();
        request.setAwemeId("3454335345");
        request.setAwemeUrl("https://api-hl.amemv.com/aweme/v1/play/?video_id=v0d00fg10000chqub8bc77u0q4inptmg&line=1&file_id=ef3e15d11fae40db94f49c8fb3be11d7&sign=8ae7630595ecd49fb598e5bbae9b19a4&is_play_url=1&source=PackSourceEnum_PUBLISH");
//        request.setContentCenterUrl("https://api-dev.afanticar.com/content-center/v1/kaize/publish/task");
        request.setContentCenterUrl("http://localhost:18902/v1/aweme/recognize");
        Date beginDate = new Date();
        log.info("begin time {}",beginDate);
        AwemeCallbackContent audio = getAudio(request,null);
        Date endDate = new Date();
        log.info("end time {} user {} ",endDate,(endDate.getTime()-beginDate.getTime()));
        System.out.println(audio);
    }

    private static AwemeCallbackContent getAudio(AwemeSimpleRequest request,Context context) {

        String url = request.getAwemeUrl();
        String awemeId = request.getAwemeId();
        String fileName = awemeId+".wav";
        String localWavPath = "/code/temp/"+ fileName;
        String ossAudioFolderPath = "recognize/audio/";
        String ossFrameFolderPath = "recognize/frame/"+awemeId+"/";
        String localFrameFolderPath = "/code/temp//aweme/"+awemeId;
        // Bucket名称, 需要预先创建。
        String bucketName = request.getBucketName();

        File folder = new File(localFrameFolderPath);
        if(!folder.exists()){
            folder.mkdirs();
        }

        // Endpoint必须填写Bucket所在地域对应的Endpoint，推荐使用内网访问地址。以华东1（杭州）为例，内网访问Endpoint为https://oss-cn-hangzhou-internal.aliyuncs.com。
        String endpoint = "https://oss-cn-hangzhou-internal.aliyuncs.com";

        // 获取密钥信息，执行前，确保函数所在的服务配置了角色信息，并且角色需要拥有AliyunOSSFullAccess权限。
        // 建议直接使用AliyunFCDefaultRole角色。
        String os = System.getProperty("os.name");
        if(os.toLowerCase().indexOf("win")!=-1){
            ffmpegPath = "ffmpeg";
            endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        }
        log.info("context {}", context);
        Credentials creds = null;
        if(context != null){
            creds = context.getExecutionCredentials();
            log.info("creds.getAccessKeyId{},creds.getAccessKeySecret{},creds.getSecurityToken{}",creds.getAccessKeyId(),creds.getAccessKeySecret(),creds.getSecurityToken());
        }

        OSS ossClient =null;
        if(context != null){
            ossClient = new OSSClientBuilder().build(endpoint, creds.getAccessKeyId(), creds.getAccessKeySecret(),creds.getSecurityToken());
        }else{
            ossClient = new OSSClientBuilder().build(endpoint, "LTAI5t9vrwhiU9RKYsggDqyd", "S8OvXGgRCZWE51WBNw16izJZ2CfQDT");
        }


        //放音频文件
        OSS finalOssClient = ossClient;
        CompletableFuture<Boolean> audioFuture = CompletableFuture.supplyAsync(() -> putAudioFile(url,fileName, localWavPath, ossAudioFolderPath, bucketName, finalOssClient));


        //抽帧及放文件
        CompletableFuture<List<String>> picFuture = CompletableFuture.supplyAsync(() -> putPicFrame(url, ossFrameFolderPath, localFrameFolderPath, bucketName, finalOssClient));

        List<String> frames = null;
        try {
            frames = picFuture.get();
        } catch (Exception e) {
            log.error("抽帧报错{}", e);
        }
        CompletableFuture.allOf(audioFuture,picFuture);
        // 关闭OSSClient。
        ossClient.shutdown();

        AwemeCallbackContent awemeContent = new AwemeCallbackContent();
        awemeContent.setAuthorId(request.getAuthorId());
        awemeContent.setPlatform(request.getPlatform());
        awemeContent.setAwemeId(awemeId);
        awemeContent.setAwemeAudioUrl(ossAudioFolderPath + fileName);
        awemeContent.setAwemeFrames(frames);
        awemeContent.setPublishTime(request.getPublishTime());
        String post = HttpUtil.post(request.getContentCenterUrl(), JSONObject.toJSONString(awemeContent));
        log.info("post {}",post);

        gc();

        return awemeContent;
    }

    private static List<String> putPicFrame(String url, String ossFrameFolderPath, String localFrameFolderPath, String bucketName, OSS ossClient) {
        List<String> frames = new ArrayList<>();
        String localFolderPath = localFrameFolderPath;
        FFmpegUtil.getFramesByPic(ffmpegPath, null, null, url,localFolderPath , "1/0.5", null, null);
        long halfSecond = 500L;

        File localFolderPathFile = new File(localFolderPath);
        if (localFolderPathFile.exists()) {

            File[] files = localFolderPathFile.listFiles();
            List<File> fileList = Arrays.asList(files);
            //文件名进行升序排序
            Collections.sort(fileList, new Comparator<File>() {
                @Override
                public int compare(File o1, File o2) {
                    return o1.getName().compareTo(o2.getName());
                }
            });
            long secondName = 0;
            for (int i = 0; i < fileList.size(); i++) {
                File file = fileList.get(i);
                secondName = halfSecond * (i + 1);
                //上传到oss里
                //上传文件
                String ossFramePath = ossFrameFolderPath + secondName + ".jpg";
                ossClient.putObject(bucketName, ossFramePath,file);
                frames.add(ossFramePath);
            }
        }
        FileUtil.del(localFolderPathFile);
        return frames;
    }

    private static Boolean putAudioFile(String url,String fileName, String localWavPath, String ossAudioFolderPath, String bucketName, OSS ossClient) {
        // 填写Byte数组。
        FFmpegUtil.live2Audio(ffmpegPath,url,localWavPath,null,null);
        File localWavPathfile = new File(localWavPath);
        PutObjectResult putObjectResult = ossClient.putObject(bucketName, ossAudioFolderPath + fileName, localWavPathfile);

        //上传完删除文件
        localWavPathfile.delete();
        return true;
    }

    /**
     * gc clean current dump
     */
    private static void gc() {
        //获取当前堆的大小 byte 单位
        long heapSize = Runtime.getRuntime().totalMemory();
        log.info("Current heap size{}m",heapSize/1024/1024);

        //获取堆的最大大小byte单位
        //超过将抛出 OutOfMemoryException
        long heapMaxSize = Runtime.getRuntime().maxMemory();
        log.info("Gets the maximum heap size{}m",heapMaxSize/1024/1024);

        //获取当前空闲的内存容量byte单位
        long heapFreeSize = Runtime.getRuntime().freeMemory();
        log.info("Gets the current free memory capacity{}m",heapFreeSize/1024/1024);

        System.gc();

        log.info("gc-after");

        heapSize = Runtime.getRuntime().totalMemory();
        log.info("Current heap size{}m",heapSize/1024/1024);

        //获取堆的最大大小byte单位
        //超过将抛出 OutOfMemoryException
        heapMaxSize = Runtime.getRuntime().maxMemory();
        log.info("Gets the maximum heap size{}m",heapMaxSize/1024/1024);

        //获取当前空闲的内存容量byte单位
        heapFreeSize = Runtime.getRuntime().freeMemory();
        log.info("Gets the current free memory capacity{}m",heapFreeSize/1024/1024);

        System.gc();
    }

}
