package com.zhongshu.card.server.core.model.upLoadFile;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.github.microservice.components.data.mongo.mongo.helper.DBHelper;
import com.github.microservice.core.util.JsonUtil;
import com.zhongshu.card.client.type.oss.DocumentType;
import com.zhongshu.card.server.core.model.upLoadFile.oss.ALiObjectStorage;
import com.zhongshu.card.server.core.model.upLoadFile.oss.SuperObjectStorage;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;

@Slf4j
@Component
public class AliObjectStorageStore extends SuperObjectStorageStore {

    @Autowired
    private DBHelper dbHelper;

    private ALiObjectStorage aLiObjectStorage;

    //持久化oss客户端对象
    private OSS ossClient;

//    public AliObjectStorageStore(String accountName, SuperObjectStorage objectStorage) {
//        super(accountName, objectStorage);
//        aLiObjectStorage = (ALiObjectStorage) objectStorage;
//        initOSSClient();
//    }

    public void setInfo(String accountName, SuperObjectStorage objectStorage) {
        super.setInfo(accountName, objectStorage);
        aLiObjectStorage = (ALiObjectStorage) objectStorage;
        initOSSClient();
    }

    /**
     * 初始化oss客户端
     */
    private void initOSSClient() {
        this.ossClient = new OSSClientBuilder().build(aLiObjectStorage.getEndpoint(), aLiObjectStorage.getAccessKeyId(), aLiObjectStorage.getAccessKeySecret());
    }


    @Override
    @SneakyThrows
    public StsToken getStsToken(Collection<String[]> allowPath) {
        //允许访问的
        final String policy = JsonUtil.toJson(new HashMap<>() {{
            put("version", "1");
            put("Statement", new Object[]{new HashMap<>() {{
                put("Action", new Object[]{"oss:PutObject"});
                put("Effect", "Allow");
                put("Resource", allowPath.stream().map((it) -> {
                    return String.format("acs:oss:*:*:%s/%s", aLiObjectStorage.getBucket(), String.join("/", it));
                }).toArray(String[]::new));
            }}});
        }});

        String regionId = "";
        // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
        DefaultProfile.addEndpoint(regionId, "Sts", "sts.aliyuncs.com");
        IClientProfile profile = DefaultProfile.getProfile(regionId, this.aLiObjectStorage.getAccessKeyId(), this.aLiObjectStorage.getAccessKeySecret());
        // 构造client。
        DefaultAcsClient client = new DefaultAcsClient(profile);
        final AssumeRoleRequest request = new AssumeRoleRequest();
        // 适用于Java SDK 3.12.0及以上版本。
        request.setSysMethod(MethodType.POST);
        request.setRoleArn(this.aLiObjectStorage.getArn());
        request.setRoleSessionName(String.format("%sSession", this.aLiObjectStorage.getAccessKeyId()));
        request.setPolicy(policy); // 如果policy为空，则用户将获得该角色下所有权限。
        request.setDurationSeconds(new BigDecimal(this.aLiObjectStorage.getStsDurationSeconds()).longValue()); // 设置临时访问凭证的有效时间为3600秒。
        final AssumeRoleResponse response = client.getAcsResponse(request);
        return StsToken.builder().token(BeanMap.create(response.getCredentials()))//token
                .bucket(this.aLiObjectStorage.getBucket())//bucket
                .paths(allowPath)//路径
                .expiredTime(this.dbHelper.getTime() + this.aLiObjectStorage.getStsDurationSeconds() * 1000L) //expiredTime
                .storageType(ObjectStorageType.ALi)//类型
                .build();
    }

    @Override
    public FileObject getFileObject(String[] path) {
        final String objectKey = String.join("/", path);
        final OSSObject ossObject = this.ossClient.getObject(this.aLiObjectStorage.getBucket(), objectKey);

        final String url = ossObject.getResponse().getUri();
        final String extName = FilenameUtils.getExtension(url);
        FileObject fileObject = FileObject.builder().url(url)//url
                .length(ossObject.getResponse().getContentLength())//length
                .documentType(DocumentType.findDocumentType(extName))//文档类型
                .build();
        return fileObject;
    }

    @Override
    public String[] uploadFileObject(String[] path, InputStream inputStream, Long length) {
        String objectName = String.join("/", path);
        PutObjectRequest putObjectRequest = new PutObjectRequest(this.aLiObjectStorage.getBucket(), objectName, inputStream);
        PutObjectResult putObjectResult = this.ossClient.putObject(putObjectRequest);
        return Arrays.stream(putObjectRequest.getKey().split("/")).filter(it -> StringUtils.hasText(it)).toArray(String[]::new);
    }

    @Override
    public boolean deleteFileObject(String[] path) {
        final String objectKey = String.join("/", path);
        this.ossClient.deleteObject(this.aLiObjectStorage.getBucket(), objectKey);
        return true;
    }


    @Override
    public void destroy() {
        log.info("destroy - {}", this);
        this.ossClient.shutdown();
    }
}
