package com.gxwebsoft.common.system.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.PolicyConditions;
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.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.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 阿里云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 RedisUtil redisUtil;
  @Resource
  private FileRecordService fileRecordService;

  @OperationLog
  @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();
    // 填写Object完整路径，完整路径中不能包含Bucket名称，例如exampledir/exampleobject.txt。
//    String objectName = "exampledir/exampleobject.txt";
    // 填写本地文件的完整路径，例如D:\\localpath\\examplefile.txt。
    // 如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
//    String filePath= "D:\\localpath\\examplefile.txt";

    // 创建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);
  }


  @OperationLog
  @ApiOperation("获取临时osstoken")
  @GetMapping("/getSTSToken")
  public ApiResult<?> getSTSToken() {
    // STS接入地址，例如sts.cn-hangzhou.aliyuncs.com。
    String endpoint = "sts.cn-shenzhen.aliyuncs.com";
    // 填写步骤1生成的RAM用户访问密钥AccessKey ID和AccessKey Secret。
    String accessKeyId = "LTAI5t8UTh8CTXEi2dYxobhj";
    String accessKeySecret = "fNdJOT4KAjrVrzHNAcSJuUCy9ZljD9";
    // 填写步骤3获取的角色ARN。
    String roleArn = "acs:ram::1194088977870561:role/ramosstest";
    // 自定义角色会话名称，用来区分不同的令牌，例如可填写为SessionTest。
    String roleSessionName = "jimeiapp";
    // 设置临时访问凭证的有效时间为3600秒。
    Long durationSeconds = 3600L;
    try {
      // regionId表示RAM的地域ID。以华东1（杭州）地域为例，regionID填写为cn-hangzhou。也可以保留默认值，默认值为空字符串（""）。
      String regionId = "";
      // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
      DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
      // 构造default profile。
      IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
      // 构造client。
      DefaultAcsClient client = new DefaultAcsClient(profile);
      final AssumeRoleRequest request = new AssumeRoleRequest();
      // 适用于Java SDK 3.12.0及以上版本。
      request.setSysMethod(MethodType.POST);
      // 适用于Java SDK 3.12.0以下版本。
      //request.setMethod(MethodType.POST);
      request.setRoleArn(roleArn);
      request.setRoleSessionName(roleSessionName);
//      request.setPolicy(policy);
      request.setDurationSeconds(durationSeconds);
      final AssumeRoleResponse response = client.getAcsResponse(request);
      return success(response);
    } catch (ClientException | com.aliyuncs.exceptions.ClientException e) {
      System.out.println("Failed：");
      System.out.println("Error message: " + e.getMessage());
      return fail(e.getMessage());

    }
  }

  /**
   * 获取前端表单提交的参数
   * @return
   */
  @ApiOperation("")
  @GetMapping("/getPostForm")
  public ApiResult<?> getPostForm(){
    String endpoint = config.getEndpoint();
    // RAM用户的访问密钥（AccessKey ID和AccessKey Secret）。
    String accessKeyId = "LTAI5t8UTh8CTXEi2dYxobhj";
    String accessKeySecret = "fNdJOT4KAjrVrzHNAcSJuUCy9ZljD9";
    // 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
    CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
    // 填写Bucket名称，例如examplebucket。
    String bucket = config.getBucketName();
    OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

    try {
      String host = "https://" + bucket + "." + endpoint;
      String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());


      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 result = new HashMap<>();
      result.put("polocyBase64",encodedPolicy);
      result.put("signature",postSignature);
      result.put("expireEndTime",expireEndTime);
      return success(result);
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
      return fail();
    }finally {
      ossClient.shutdown();
    }

  }

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