package com.ruoyi.controller;

import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.cos.auth.COSSigner;
import com.ruoyi.response.ResponseData;
import com.ruoyi.system.service.ISysDictDataService;
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 io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * @Author OCS
 * @Date 2022/2/8 16:40
 */
@CrossOrigin
@RestController
@Slf4j
@RequestMapping("/api/cos")
@Api(tags = "OCS")
public class ApiOcsController {


    @Autowired
    private ISysDictDataService iSysDictDataService;

    // 根据 github 提供的 maven 集成方法导入 java sts sdk，使用 3.1.1 及更高版本
    public static void main(String[] args) {
        TreeMap<String, Object> config = new TreeMap<String, Object>();
        try {
            //这里的 SecretId 和 SecretKey 代表了用于申请临时密钥的永久身份（主账号、子账号等），子账号需要具有操作存储桶的权限。
            String secretKey = "VXZWQPYaedvMC6vovAU3gJ1ogXXdvO1n";
            String secretId = "AKIDSBQuX5mAZvHa2jNwSzWE0lNvNuMjA9gC";

            String region = "ap-shanghai";
            String bucket = "ddht-1324395003";
            // 替换为您的云 api 密钥 SecretId
            config.put("secretId", secretId);
            // 替换为您的云 api 密钥 SecretKey
            config.put("secretKey", secretKey);

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

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

            // 临时密钥有效时长，单位是秒，默认 1800 秒，目前主账号最长 2 小时（即 7200 秒），子账号最长 36 小时（即 129600）秒
            config.put("durationSeconds", 1800);
            // 换成您的 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/" + bucket.split("-")[1] + ":" + bucket + "/*",
                    "qcs::ci:" + region + ":uid/" + bucket.split("-")[1] + ":bucket/" + bucket + "/*"});

//            String secretKey = "VXZWQPYaedvMC6vovAU3gJ1ogXXdvO1n";
//            String secretId = "AKIDSBQuX5mAZvHa2jNwSzWE0lNvNuMjA9gC";
//
//            String region = "ap-shanghai";
//            String bucket = "ddht-1324395003";
            statement.addResources(new String[]{
                    "qcs::cos:ap-shanghai:uid/1324395003:ddht-1324395003/*",
                    "qcs::ci:ap-shanghai:uid/1324395003:bucket/ddht-1324395003/*"});

            // 把一条 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);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("no valid secret !");
        }
    }



    // 根据 github 提供的 maven 集成方法导入 java sts sdk，使用 3.1.1 及更高版本
    @PostMapping("/signNew")
    public ResponseData signNew() {

        TreeMap<String, Object> config = new TreeMap<String, Object>();
        try {

            String secretKey = "VXZWQPYaedvMC6vovAU3gJ1ogXXdvO1n";
            String secretId = "AKIDSBQuX5mAZvHa2jNwSzWE0lNvNuMjA9gC";

            String region = "ap-shanghai";
            String bucket = "ddht-1324395003";

            SysDictData sysDictData = new SysDictData();
            sysDictData.setDictType("storing_param");
            List<SysDictData> list = iSysDictDataService.selectDictDataList(sysDictData);
            for (SysDictData data : list) {
                if ("Region".equals(data.getCode())) {
                    region = data.getDictValue();
                }
                if ("Bucket".equals(data.getCode())) {
                    bucket = data.getDictValue();
                }
                if ("SecretKey".equals(data.getCode())) {
                    secretKey = data.getDictValue();
                }
                if ("SecretId".equals(data.getCode())) {
                    secretId = data.getDictValue();
                }
            }
            // 替换为您的云 api 密钥 SecretId
            config.put("secretId", secretId);
            // 替换为您的云 api 密钥 SecretKey
            config.put("secretKey", secretKey);

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

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

            // 临时密钥有效时长，单位是秒，默认 1800 秒，目前主账号最长 2 小时（即 7200 秒），子账号最长 36 小时（即 129600）秒
            config.put("durationSeconds", 1800);
            // 换成您的 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/" + bucket.split("-")[1] + ":" + bucket + "/*",
                    "qcs::ci:" + region + ":uid/" + bucket.split("-")[1] + ":bucket/" + 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 ResponseData.success(response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("no valid secret !");
        }

    }

    @PostMapping("/sign")
    public ResponseData sign(@RequestParam(value = "name") @NotBlank(message = "文件名称不能为空") String name) {

        String region = "ap-shanghai";
        String bucket = "ddht-1324395003";
        String secretKey = "VXZWQPYaedvMC6vovAU3gJ1ogXXdvO1n";
        String secretId = "AKIDSBQuX5mAZvHa2jNwSzWE0lNvNuMjA9gC";

        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType("storing_param");
        List<SysDictData> list = iSysDictDataService.selectDictDataList(sysDictData);
        for (SysDictData data : list) {
            if ("Region".equals(data.getCode())) {
                region = data.getDictValue();
            }
            if ("Bucket".equals(data.getCode())) {
                bucket = data.getDictValue();
            }
            if ("SecretKey".equals(data.getCode())) {
                secretKey = data.getDictValue();
            }
            if ("SecretId".equals(data.getCode())) {
                secretId = data.getDictValue();
            }
        }

        long startTimestamp = System.currentTimeMillis() / 1000;
        long endTimestamp = startTimestamp + 30 * 60;
        String endTimestampStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").
                format(endTimestamp * 1000);
        String keyTime = startTimestamp + ";" + endTimestamp;
        String boundary = "----WebKitFormBoundaryZBPbaoYE2gqeB21N";
        // 设置表单的body字段值
        Map<String, String> formFields = new HashMap<>();
        formFields.put("q-sign-algorithm", "sha1");
        formFields.put("key", name);
        formFields.put("q-ak", secretId);
        formFields.put("q-key-time", keyTime);
        // 构造policy，参考文档: https://cloud.tencent.com/document/product/436/14690
        String policy = "{\n" +
                "    \"expiration\": \"" + endTimestampStr + "\",\n" +
                "    \"conditions\": [\n" +
                "        { \"bucket\": \"" + bucket + "\" },\n" +
                "        { \"q-sign-algorithm\": \"sha1\" },\n" +
                "        { \"q-ak\": \"" + secretId + "\" },\n" +
                "        { \"q-sign-time\":\"" + keyTime + "\" }\n" +
                "    ]\n" +
                "}";
        // policy需要base64后算放入表单中
        String encodedPolicy = new String(Base64.encodeBase64(policy.getBytes()));
        // 设置policy
        formFields.put("policy", encodedPolicy);
        // 根据编码后的policy和secretKey计算签名
        COSSigner cosSigner = new COSSigner();
        String signature = cosSigner.buildPostObjectSignature(secretKey,
                keyTime, policy);
        // 设置签名
        formFields.put("q-signature", signature);
        String urlStr = "https://" + bucket + ".cos." + region + ".myqcloud.com";
        formFields.put("host", urlStr);
        formFields.put("bucket", bucket);
        formFields.put("region", region);
        formFields.put("secretId", secretId);
        formFields.put("secretKey", secretKey);
        return ResponseData.success(formFields);
    }

}
