package com.fs.course.service.impl;

import com.fs.common.core.domain.R;
import com.fs.course.domain.FsUserCourseVideo;
import com.fs.course.mapper.FsUserCourseVideoMapper;
import com.fs.course.service.ITencentCloudCosService;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
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.model.ObjectMetadata;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.utils.IOUtils;
import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Policy;
import com.tencent.cloud.Response;
import com.tencent.cloud.Statement;
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 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
public class TencentCloudCosService implements ITencentCloudCosService {
    private static final String RT_SECRET_ID = "AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX";
    private static final String RT_SECRET_KEY = "lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT";
    private static final String RT_BUCKET = "fs-1319721001";
    private static final String RT_APP_ID = "1319721001";
    private static final String RT_REGION = "ap-chongqing";
    private static final String RT_PROXY = "fs";


    private static final String YL_SECRET_ID = "AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT";
    private static final String YL_SECRET_KEY = "u5SuS80342xzx8FRBukza9lVNHKNMSaB";
    private static final String YL_BUCKET = "jiuzhou-1323137866";
    private static final String YL_APP_ID = "1323137866";
    private static final String YL_REGION = "ap-chongqing";
    private static final String YL_PROXY = "jiuzhou";
    @Override
    public R getTmpSecretKey() {
        TreeMap<String, Object> config = new TreeMap<String, Object>();
        try {
            //这里的 SecretId 和 SecretKey 代表了用于申请临时密钥的永久身份（主账号、子账号等），子账号需要具有操作存储桶的权限。
            String secretId = "AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX";//用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
            String secretKey = "lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT";//用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
            String bucket = "fs-1319721001";
            String appId = "1319721001";
            String region = "ap-chongqing";
            String proxy  = "fs";
            int durationSeconds = 1800;

            // 替换为您的云 api 密钥 SecretId
            config.put("secretId", secretId);
            // 替换为您的云 api 密钥 SecretKey
            config.put("secretKey", secretKey);

            // 初始化 policy
            Policy policy = new Policy();

            // 设置域名:
            // 如果您使用了腾讯云 cvm，可以设置内部域名
            config.put("host", "https://cos.his.cdwjyyh.com");

            // 临时密钥有效时长，单位是秒，默认 1800 秒，目前主账号最长 2 小时（即 7200 秒），子账号最长 36 小时（即 129600）秒
            config.put("durationSeconds", durationSeconds);
            // 换成您的 bucket
            config.put("bucket", bucket);
            // 换成 bucket 所在地区
            config.put("region", region);

            // 开始构建一条 statement
            Statement statement = new Statement();
            // 声明设置的结果是允许操作
            statement.setEffect("allow");
            /**
             * 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。
             * 权限列表请参见 https://cloud.tencent.com/document/product/436/31923
             * 规则为 {project}:{interfaceName}
             * project : 产品缩写  cos相关授权为值为cos,数据万象(数据处理)相关授权值为ci
             * 授权所有接口用*表示，例如 cos:*,ci:*
             * 添加一批操作权限 :
             */
            statement.addActions(new String[]{
                    "cos:PutObject",
                    // 表单上传、小程序上传
                    "cos:PostObject",
                    // 分块上传
                    "cos:InitiateMultipartUpload",
                    "cos:ListMultipartUploads",
                    "cos:ListParts",
                    "cos:UploadPart",
                    "cos:CompleteMultipartUpload",
                    // 处理相关接口一般为数据万象产品 权限中以ci开头
                    // 创建媒体处理任务
                    "ci:CreateMediaJobs",
                    // 文件压缩
                    "ci:CreateFileProcessJobs"
            });

            /**
             * 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径
             * 资源表达式规则分对象存储(cos)和数据万象(ci)两种
             * 数据处理、审核相关接口需要授予ci资源权限
             *  cos : qcs::cos:{region}:uid/{appid}:{bucket}/{path}
             *  ci  : qcs::ci:{region}:uid/{appid}:bucket/{bucket}/{path}
             * 列举几种典型的{path}授权场景：
             * 1、允许访问所有对象："*"
             * 2、允许访问指定的对象："a/a1.txt", "b/b1.txt"
             * 3、允许访问指定前缀的对象："a*", "a/*", "b/*"
             *  如果填写了“*”，将允许用户访问所有资源；除非业务需要，否则请按照最小权限原则授予用户相应的访问权限范围。
             *
             * 示例：授权examplebucket-1250000000 bucket目录下的所有资源给cos和ci 授权两条Resource
             */
            statement.addResources(new String[]{
                    "qcs::cos:" + region + ":uid/" + appId + ':' + bucket + "/*" });

            // 把一条 statement 添加到 policy
            // 可以添加多条
            policy.addStatement(statement);
            // 将 Policy 示例转化成 String，可以使用任何 json 转化方式，这里是本 SDK 自带的推荐方式
            config.put("policy", Jackson.toJsonPrettyString(policy));

            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 !");
        }
    }

    @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 static 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 = YL_SECRET_ID;//用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
        String secretKey = YL_SECRET_KEY; ;//用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140

//          String  secretId = YL_SECRET_ID;
//            String  secretKey = YL_SECRET_KEY;
        String bucket = YL_BUCKET;
        String appId = YL_APP_ID;
        String region = YL_REGION;
        String proxy = YL_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 static COSClient cosClient = createClient();

    private static COSClient createClient() {
        // 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(YL_SECRET_ID,YL_SECRET_KEY);
        // 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(YL_REGION));
        // 生成cos客户端
        COSClient cosclient = new COSClient(cred, clientConfig);

        return cosclient;
    }

    private static byte[] getObjectInputStream() throws IOException {
        String key = "test/my_test.json";
        GetObjectRequest getObjectRequest = new GetObjectRequest(YL_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 static MpsClient createMpsClient() {
        Credential cred = new Credential(YL_SECRET_ID, YL_SECRET_KEY);
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("mps.tencentcloudapi.com");
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        return new MpsClient(cred, YL_REGION, clientProfile);
    }
    public static String replaceCourse(String input) {
        if (input == null) {
            return null;
        }
        return input.replace("course", "course_transcode_100301");
    }

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


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


            // 输出配置
            CosOutputStorage cosOutputStorage = new CosOutputStorage();
            cosOutputStorage.setBucket(YL_BUCKET);
            cosOutputStorage.setRegion(YL_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();
        }
    }
}
