package com.njzscloud.common.minio.util;


import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PolicyConditions;
import com.njzscloud.common.core.tuple.Tuple2;
import com.njzscloud.common.minio.config.MinioProperties;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class AliOSS {
    private static final OSS CLIENT;
    private static final String BUCKET_NAME;
    private static final String ACCESS_KEY;

    static {
        CLIENT = SpringUtil.getBean(OSS.class);
        BUCKET_NAME = SpringUtil.getBean(MinioProperties.class).getBucketName();
        ACCESS_KEY = SpringUtil.getBean(MinioProperties.class).getAccessKey();
        if (StrUtil.isNotBlank(BUCKET_NAME)) {
            createBucket(BUCKET_NAME);
        }
    }

    public static void createBucket(String bucketName) {
        Assert.notBlank(bucketName, "未指明存储位置");
        try {
            boolean exists = CLIENT.doesBucketExist(bucketName);
            if (exists) return;
            CLIENT.createBucket(bucketName);
        } catch (Exception e) {
            log.error("存储桶创建失败", e);
        }
    }

    public static Map<String, String> obtainPresignedUrl(String objectName) {
        Map<String, String> data = new HashMap<>();
        try {
            long expireEndTime = System.currentTimeMillis() + 3600 * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            String postPolicy = CLIENT.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = CLIENT.calculatePostSignature(postPolicy);
            data.put("OSSAccessKeyId", ACCESS_KEY);
            data.put("policy", encodedPolicy);
            data.put("signature", postSignature);
            data.put("success_action_status", "200");
            data.put("name", objectName);
            data.put("key", objectName);
            data.put("bucketName", BUCKET_NAME);
            data.put("objectName", objectName);
        } 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("HTTP Status Code: " + oe.getRawResponseError());
            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());
        }
        return data;
    }

    public static Tuple2<InputStream, String> obtainFile(String bucketName, String objectName) {
        try {
            // 下载Object到本地文件，并保存到指定的本地路径中。如果指定的本地文件存在会覆盖，不存在则新建。
            // 如果未指定本地路径，则下载后的文件默认保存到示例程序所属项目对应本地路径中。
            OSSObject response = CLIENT.getObject(new GetObjectRequest(bucketName, objectName));
            ObjectMetadata objectMetadata = response.getObjectMetadata();
            String contentType = objectMetadata.getContentType();
            InputStream objectContent = response.getObjectContent();
            return Tuple2.create(objectContent, contentType);

        } 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());
        }
        return null;
    }

}
