package com.fs.course.service.impl;

import com.fs.common.core.domain.R;
import com.fs.config.tencent.TencentProperties;
import com.fs.course.domain.FsUserCourseVideo;
import com.fs.course.mapper.FsUserCourseVideoMapper;
import com.fs.course.service.ITencentCloudCosService;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.COSObject;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.utils.IOUtils;
import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Response;
import com.tencent.cloud.cos.util.Jackson;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.mps.v20190612.MpsClient;
import com.tencentcloudapi.mps.v20190612.models.*;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@AllArgsConstructor
public class TencentCloudCosService implements ITencentCloudCosService {
    private final COSClient cosClient;
    private final TencentProperties tencentProperties;


    @Override
    public R getKeyAndCredentials() {
        TreeMap config = this.getConfig();

        try {
            Response response = CosStsClient.getCredential(config);
            System.out.println(response.credentials.tmpSecretId);
            System.out.println(response.credentials.tmpSecretKey);
            System.out.println(response.credentials.sessionToken);
            return R.ok().put("data",response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("no valid secret !");
        }
    }

    public String generateCosKey(String ext) {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String ymd = dateFormat.format(date);

        Random random = new Random();
        int r = random.nextInt(1000000);
        String rStr = String.format("%06d", r);

        String cosKey = String.format("file/%s/%s_%s.%s", ymd, ymd, rStr, ext != null ? ext : "");
        return cosKey;
    }

    public TreeMap<String,Object> getConfig(){

        String secretId = tencentProperties.secretId;//用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
        String secretKey = tencentProperties.secretKey; ;//用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140

//          String  secretId = YL_SECRET_ID;
//            String  secretKey = YL_SECRET_KEY;
        String bucket = tencentProperties.bucket;
        String appId = tencentProperties.appId;
        String region = tencentProperties.region;
        String proxy = tencentProperties.proxy;


        int durationSeconds = 1800;

//        String[] segments = filename.split("\\.");
//        String ext = segments.length > 0 ? segments[segments.length - 1] : "";

        // 临时密钥限制
        Boolean limitExt = false; // 限制上传文件后缀
//        List extWhiteList = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp"); // 限制的上传后缀
        Boolean limitContentType = false; // 限制上传 contentType
        Boolean limitContentLength = false; // 限制上传文件大小


        Map<String, Object> condition = new HashMap();

        // 1. 限制上传文件后缀
//        if (limitExt) {
//            boolean extInvalid = ext == null || !extWhiteList.contains(ext);
//            if (extInvalid) {
//                System.out.println("非法文件，禁止上传");
//                return null;
//            }
//        }

        // 2. 限制上传文件 content-type
        if (limitContentType) {
            condition.put("string_like", new HashMap<String, String>() {{
                put("cos:content-type", "image/*");
            }});
        }

        // 3. 限制上传文件大小
        if (limitContentLength) {
            condition.put("numeric_less_than_equal", new HashMap<String, Long>() {{
                put("cos:content-length", 5L * 1024 * 1024);
            }});
        }

        String resource = "qcs::cos:" + region + ":uid/" + appId + ':' + bucket + '/' +"*";
        List allowActions = Arrays.asList(
                // 简单上传
                "name/cos:PutObject",
                // 分块上传
                "name/cos:InitiateMultipartUpload",
                "name/cos:ListMultipartUploads",
                "name/cos:ListParts",
                "name/cos:UploadPart",
                "name/cos:CompleteMultipartUpload"
        );


        // 构建policy
        Map<String, Object> policy = new HashMap();
        policy.put("version", "2.0");
        Map<String, Object> statement = new HashMap();
        statement.put("action", allowActions);
        statement.put("effect", "allow");
        List<String> resources = Arrays.asList(
                resource
        );
        statement.put("resource", resources);
        statement.put("condition", condition);
        policy.put("statement", Arrays.asList(statement));


        // 构建config
        TreeMap <String,Object> config = new TreeMap<String, Object>();
        config.put("secretId",secretId);
        config.put("secretKey",secretKey);
        config.put("proxy",proxy);
        config.put("duration",durationSeconds);
        config.put("bucket",bucket);
        config.put("region",region);
//        config.put("host", "https://cos.his.cdwjyyh.com");
        config.put("policy",Jackson.toJsonPrettyString(policy));
        return config;
    }

    @Override
    @Transactional
    public R updateUrl() {
        try {
            //查出已转码的视频并且没有文件key的
            List<FsUserCourseVideo> videos =  courseVideoMapper.selectVideoIsTranscode();
            for (FsUserCourseVideo video : videos ){
                String newUrl = replaceCourse(video.getLineOne());
                FsUserCourseVideo videoMap = new FsUserCourseVideo();
                videoMap.setVideoId(video.getVideoId());
                videoMap.setLineOne(newUrl);
                videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
                courseVideoMapper.updateFsUserCourseVideo(videoMap);
            }
            return R.ok();
        }catch (Exception e){
            return R.error();
        }

    }

    private byte[] getObjectInputStream() throws IOException {
        String key = "test/my_test.json";
        GetObjectRequest getObjectRequest = new GetObjectRequest(tencentProperties.bucket, key);
        InputStream cosObjectInput = null;

        try {
            COSObject cosObject = cosClient.getObject(getObjectRequest);
            cosObjectInput = cosObject.getObjectContent();
        } catch (CosServiceException e) {
            e.printStackTrace();
        } catch (CosClientException e) {
            e.printStackTrace();
        }

        // 处理下载到的流
        // 这里是直接读取，按实际情况来处理
        byte[] bytes = null;
        try {
            bytes = IOUtils.toByteArray(cosObjectInput);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 用完流之后一定要调用 close()
            cosObjectInput.close();
        }
        return bytes;
    }

    @Autowired
    private FsUserCourseVideoMapper courseVideoMapper;

    /**
     * 批量转码
     * @return
     */
    @Override
    public R videoTranscode() {
        //查出未转码的视频
        List<FsUserCourseVideo> videos =  courseVideoMapper.selectVideoTranscode(0);
        for (FsUserCourseVideo video : videos ){
            String inputPath = "/"+video.getFileKey();
            String outputPath = "/"+replaceCourse(video.getFileKey());
            submitTranscodeJob(inputPath,outputPath);
            FsUserCourseVideo videoMap = new FsUserCourseVideo();
            videoMap.setVideoId(video.getVideoId());
            videoMap.setIsTranscode(1);
            courseVideoMapper.updateFsUserCourseVideo(videoMap);
        }

        return R.ok();
    }

    private MpsClient createMpsClient() {
        Credential cred = new Credential(tencentProperties.secretId, tencentProperties.secretKey);
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("mps.tencentcloudapi.com");
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        return new MpsClient(cred, tencentProperties.region, clientProfile);
    }
    public String replaceCourse(String input) {
        if (input == null) {
            return null;
        }
        return input.replace("course", "course_transcode_100301");
    }

    public void submitTranscodeJob(String inputPath,String outputPath) {
        try {
            // 输入文件配置（COS路径）
            MpsClient client = createMpsClient();
            CosInputInfo cosInputInfo = new CosInputInfo();
            cosInputInfo.setBucket(tencentProperties.bucket);
            cosInputInfo.setRegion(tencentProperties.region);
            //文件key
            cosInputInfo.setObject(inputPath);


            MediaInputInfo inputInfo = new MediaInputInfo();
            inputInfo.setType("COS");
            inputInfo.setCosInputInfo(cosInputInfo);


            // 输出配置
            CosOutputStorage cosOutputStorage = new CosOutputStorage();
            cosOutputStorage.setBucket(tencentProperties.bucket);
            cosOutputStorage.setRegion(tencentProperties.region);

            TaskOutputStorage taskOutputStorage = new TaskOutputStorage();
            taskOutputStorage.setType("COS");
            taskOutputStorage.setCosOutputStorage(cosOutputStorage);

            TranscodeTaskInput transcodeInput = new TranscodeTaskInput();
            transcodeInput.setDefinition(100301L);
            transcodeInput.setOutputStorage(taskOutputStorage);
            transcodeInput.setOutputObjectPath(outputPath);

            // 构建任务请求
            ProcessMediaRequest req = new ProcessMediaRequest();
            req.setInputInfo(inputInfo);

            MediaProcessTaskInput task = new MediaProcessTaskInput();
            task.setTranscodeTaskSet(new TranscodeTaskInput[]{transcodeInput});

            req.setMediaProcessTask(task);

            // 提交任务
            ProcessMediaResponse resp = client.ProcessMedia(req);
            System.out.println("任务提交成功，JobId: " + resp.getTaskId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
