package com.njzscloud.common.oss.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.ex.Exceptions;
import com.njzscloud.common.core.tuple.Tuple2;
import com.njzscloud.common.oss.config.OSSProperties;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
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);
        OSSProperties ossProperties = SpringUtil.getBean(OSSProperties.class);
        OSSProperties.AliProperties ali = ossProperties.getAli();
        BUCKET_NAME = ali.getBucketName();
        ACCESS_KEY = ali.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) {
        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);
            Map<String, String> data = new HashMap<>();
            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);
            return data;
        } catch (OSSException oe) {
            log.error("阿里云获取上传链接失败,错误信息：{}、错误码：{}、请求标识：{}、主机标识：{}、存储桶：{}、对象名称：{}",
                    oe.getErrorMessage(),
                    oe.getErrorCode(),
                    oe.getRequestId(),
                    oe.getHostId(),
                    BUCKET_NAME,
                    objectName);
            throw Exceptions.error("文件服务器错误");
        } catch (ClientException ce) {
            log.error("阿里云获取上传链接失败,错误信息：{}、存储桶：{}、对象名称：{}",
                    ce.getMessage(),
                    BUCKET_NAME,
                    objectName);
            throw Exceptions.error("文件服务器错误");
        }
    }

    public static Tuple2<InputStream, String> obtainFile(String bucketName, String objectName) {
        try {
            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) {
            log.error("阿里云下载文件失败,错误信息：{}、错误码：{}、请求标识：{}、主机标识：{}、存储桶：{}、对象名称：{}",
                    oe.getErrorMessage(),
                    oe.getErrorCode(),
                    oe.getRequestId(),
                    oe.getHostId(),
                    bucketName,
                    objectName);
            // throw Exceptions.error("文件服务器错误");
        } catch (ClientException ce) {
            log.error("阿里云下载文件失败,错误信息：{}、存储桶：{}、对象名称：{}",
                    ce.getMessage(),
                    bucketName,
                    objectName);
            // throw Exceptions.error("文件服务器错误");
        }
        return Tuple2.create(new ByteArrayInputStream(new byte[0]), "");
    }

    public static String uploadFile(String objectName, String contentType, InputStream inputStream) {
        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            if (StrUtil.isNotBlank(contentType)) objectMetadata.setContentType(contentType);
            CLIENT.putObject(BUCKET_NAME, objectName, inputStream, objectMetadata);
            return "/" + BUCKET_NAME + "/" + objectName;
        } catch (OSSException oe) {
            log.error("阿里云上传文件失败,错误信息：{}、错误码：{}、请求标识：{}、主机标识：{}、存储桶：{}、对象名称：{}",
                    oe.getErrorMessage(),
                    oe.getErrorCode(),
                    oe.getRequestId(),
                    oe.getHostId(),
                    BUCKET_NAME,
                    objectName);
            throw Exceptions.error("文件服务器错误");
        } catch (ClientException ce) {
            log.error("阿里云上传文件失败,错误信息：{}、存储桶：{}、对象名称：{}",
                    ce.getMessage(),
                    BUCKET_NAME,
                    objectName);
            throw Exceptions.error("文件服务器错误");
        }
    }
}
