package com.gxwebsoft.common.system.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.CloudTopic;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.common.http.ClientConfiguration;
import com.aliyun.mns.model.Message;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.*;
import com.aliyuncs.auth.AlibabaCloudCredentialsProvider;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.cms.entity.Article;
import com.gxwebsoft.cms.service.ArticleService;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.FileServerUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.FileRecord;
import com.gxwebsoft.common.system.service.FileRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.Base64;

/**
 * 阿里云OSS云存储
 *
 * @author WebSoft
 * @since 2022-11-19 13:54:27
 */
@Api(tags = "阿里云OSS云存储")
@RestController
@RequestMapping("/api/oss")
public class AliOssController extends BaseController {
    @Resource
    private ConfigProperties config;
    @Resource
    private ArticleService articleService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private FileRecordService fileRecordService;

//    String accessKeyId = "LTAI5tGZwF9Pz1S9weuKMFe5";
//    String accessKeySecret = "KVP7IIxaWkwS4Bz5UKqE63hxIbs61H";
//    String accessKeyId = "LTAI4GKGZ9Z2Z8JZ77c3GNZP";
//    String accessKeySecret = "BiDkpS7UXj72HWwDWaFZxiXjNFBNCM";
//    String bucket = "oss-gxwebsoft";
//    String region = "cn-shenzhen";
//    String endpoint = "https://oss-cn-shenzhen.aliyuncs.com";

    String accessKeyId = "LTAI5tCqrMCF2VfCnuYutGnV";
    String accessKeySecret = "FQMnh7F7AnifC2dFpFrqYPZA5ngE11";
    String bucket = "nbg-oss";
    String region = "cn-shenzhen";
    String endpoint = "https://oss-cn-shenzhen.aliyuncs.com";

    String host = "https://oss.wsdns.com";

    public AliOssController() throws com.aliyuncs.exceptions.ClientException {

    }

    
    @ApiOperation("上传文件")
    @PostMapping("/upload")
    public ApiResult<FileRecord> upload(@RequestParam MultipartFile file, HttpServletRequest request) throws Exception {
        FileRecord result = null;
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = config.getEndpoint();
        // RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
        String accessKeyId = config.getAccessKeyId();
        String accessKeySecret = config.getAccessKeySecret();
        // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        // 填写Bucket名称，例如examplebucket。
        String bucketName = config.getBucketName();

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {

            String dir = getUploadDir();
            File upload = FileServerUtil.upload(file, dir, config.getUploadUuidName());
            String path = upload.getAbsolutePath().replace("\\", "/").substring(dir.length());
            String originalName = file.getOriginalFilename();

            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path, upload);
            // 如果需要上传时设置存储类型和访问权限，请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 上传文件。
            PutObjectResult ossResult = ossClient.putObject(putObjectRequest);

            // 保存记录并返回
            String requestURL = config.getBucketDomain();
            final String domain = redisUtil.getUploadConfig(getTenantId()).get("bucketDomain");
            if (StrUtil.isNotBlank(domain)) {
                requestURL = domain;
            }
            path = "/".concat(path);
            upload.delete();
            final String cache = redisUtil.get("setting:upload:" + getTenantId());
            final JSONObject jsonObject = JSONObject.parseObject(cache);
            final String bucketDomain = jsonObject.getString("bucketDomain");
            if (StrUtil.isNotBlank(bucketDomain)) {
                requestURL = bucketDomain;
            }
            result = new FileRecord();
            result.setCreateUserId(getLoginUserId());
            result.setName(StrUtil.isBlank(originalName) ? upload.getName() : originalName);
            result.setLength(upload.length());
            result.setPath(requestURL + path);
            result.setThumbnail(requestURL + path + "?x-oss-process=image/resize,m_fixed,w_100,h_100/quality,Q_90");
            result.setUrl(requestURL + path + "?x-oss-process=image/resize,w_750/quality,Q_90");
            result.setDownloadUrl(requestURL + path);
            String contentType = FileServerUtil.getContentType(upload);
            result.setContentType(contentType);
            fileRecordService.save(result);
            return success(result);

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return fail("上传失败", null);
    }

    @ApiOperation("获取临时osstoken")
    @GetMapping("/getSTSToken")
    public ApiResult<?> getSTSToken() {
        String endpoint = config.getEndpoint();
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            long expireTime = 60;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 100 * 1024 * 1024);


            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);
            Map<String, Object> result = new HashMap<>();
            result.put("accessKeyId", accessKeyId);
            result.put("token", credentialsProvider.getCredentials().getSecurityToken());
            result.put("policy", encodedPolicy);
            result.put("signature", postSignature);
            result.put("expireEndTime", expireEndTime);
            return success(result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return fail();
        } finally {
            ossClient.shutdown();
        }
    }

    /***
     * 视频转码
     * @param sourceKey 源视频
     */
    public void videoTrans(String sourceKey) {
        // 创建OSSClient实例。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();
        try {
            // 构建视频处理样式字符串以及视频转码处理参数。
            String style = "video/convert,f_mp4,vcodec_h264,s_720x1280,scaletype_fill,vb_1000000,fps_30,acodec_aac,ab_100000,sn_1";
            // 构建异步处理指令。
            String target = "videoTrans/" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd") + "/" + RandomUtil.randomString(32) + ".mp4";
            String bucketEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString(bucket.getBytes());
            String targetEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString(target.getBytes());
            String notifyEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString("nbg-video-trans".getBytes());
            String process = String.format("%s|sys/saveas,b_%s,o_%s/notify,topic_%s", style, bucketEncoded, targetEncoded, notifyEncoded);
            // 创建AsyncProcessObjectRequest对象。
            AsyncProcessObjectRequest request = new AsyncProcessObjectRequest(bucket, sourceKey, process);
            // 执行异步处理任务。
            AsyncProcessObjectResult response = ossClient.asyncProcessObject(request);

        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
    }

    public void pullVideoTrans() {
        CloudAccount account = new CloudAccount(accessKeyId, accessKeySecret, "https://1470199532233684.mns.cn-shenzhen.aliyuncs.com");
        //this client need only initialize once
        MNSClient client = account.getMNSClient();
        CloudQueue queue = client.getQueueRef("nbg");
        try {
            Message messages = queue.popMessage();
            if (messages != null) {
                String body = messages.getMessageBodyAsRawString();
                JSONObject jsonObject = JSONObject.parseObject(body);
                String messageContent = jsonObject.getString("Message");
                System.out.println(messageContent);
                String sourceStr = JSONObject.parseObject(JSONObject.parseObject(messageContent).getString("content")).getString("Sources");
                String targetStr = JSONObject.parseObject(JSONObject.parseObject(messageContent).getString("content")).getString("Targets");
                JSONArray sourceList = JSONArray.parseArray(sourceStr);
                JSONArray targetList = JSONArray.parseArray(targetStr);
                for (int i = 0; i < sourceList.size(); i++) {
                    JSONObject source = sourceList.getJSONObject(i);
                    JSONObject target = targetList.getJSONObject(i);
                    String[] sourceStrList = source.getString("URI").split("/");
                    String[] targetStrList = target.getString("URI").split("/");
                    String sourceKey = sourceStrList[sourceStrList.length - 2] + "/" + sourceStrList[sourceStrList.length - 1];
                    Article article = articleService.getOne(
                            new LambdaQueryWrapper<Article>().like(Article::getImage, sourceKey)
                                    .last("limit 1")
                    );
                    if (article != null) {
                        String targetKey = "https://oss.wsdns.cn/videoTrans/" + targetStrList[targetStrList.length - 2] + "/" + targetStrList[targetStrList.length - 1];
                        article.setVideo(targetKey);
                        articleService.updateById(article);
                    }
                }
//        System.out.println(sourceList);
//        System.out.println(targetList);
                if (messages.getReceiptHandle() != null) queue.deleteMessage(messages.getReceiptHandle());
            }
        } catch (Exception e) {
//            System.out.println(e.getMessage());
        }
    }

    /**
     * 文件上传位置(服务器)
     */
    private String getUploadDir() {
        return config.getUploadPath() + "file/";
    }
}
