package io.renren.common.utils;

import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import io.minio.Result;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import io.renren.modules.sys.entity.algs.FileTest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @Author: Ivan Q
 * @Date: 2021/6/10 19:49
 */
@Slf4j
public class MinIoUtils {
    private static MinioClient minioClient;
    private static String endpoint;
    private static String accessKey;
    private static String secretKey;

    public MinIoUtils() {
    }
    public MinIoUtils(String endpoint,String accessKey,String secretKey) {
        MinIoUtils.endpoint=endpoint;
        MinIoUtils.accessKey=accessKey;
        MinIoUtils.secretKey=secretKey;
        createMinioClient();
    }

    /**
     * Description 创建minIOClient
     */
    public void createMinioClient(){
        try {
            minioClient=new MinioClient(endpoint,accessKey,secretKey);
        } catch (InvalidEndpointException e) {
            e.printStackTrace();
        } catch (InvalidPortException e) {
            e.printStackTrace();
        }
    }

    /**
     * Description 根据存储桶名称查看该桶是否已经存在
     * @param bucketName
     * @return
     */
    public static boolean isBucketExists(String bucketName)
            throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        return minioClient.bucketExists(bucketName);
    }

    /**
     * Description 创建存储桶
     * @param bucketName 存储桶名称
     */
    public static void createBucket(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, RegionConflictException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        if(!minioClient.bucketExists(bucketName))   minioClient.makeBucket(bucketName);
    }

    /**
     * Description 获取目标文件url
     * @param bucket 文件所在桶名称
     * @param fileName 文件名(包括所在文件夹名)
     * @return
     */
    public static String getFileUrl(String bucket,String fileName){
        String objectUrl="";
        try {
            objectUrl= minioClient.getPresignedObjectUrl(Method.GET,bucket,fileName,1000,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return objectUrl;
    }

    /**
     * Description:获取指定文件的InputStream
     * @param bucketName
     * @param objectName
     * @return
     */
    public static InputStream getFileInputStream(String bucketName,String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        return minioClient.getObject(bucketName,objectName);

    }

    /**
     * 测试从minio下载文件到指定本地目录
     * @param bucketName minio桶名
     * @param objectName minio文件名
     * @param fileName 本地地址
     */
    public static void downloadFile(String bucketName,String objectName,String fileName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        minioClient.getObject(bucketName,objectName,fileName);
    }


    /**
     * Description 上传本地文件到minio
     * @param bucketName 上传文件所在存储桶
     * @param minioFileName 上传到minio的文件名
     * @param localFileName 本地文件名称，即路径名/文件名
     * @param options 上传选项
     */
    public static void uploadLocalFile(String bucketName, String minioFileName, String localFileName, PutObjectOptions options)
            throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        minioClient.putObject(bucketName,minioFileName,localFileName,options);
    }


    /**
     * Description 上传MultipartFile种类文件到minio，若存在同名文件会被覆盖
     * @param file MultipartFile文件对象
     * @param bucketName 存储桶名称
     */
    public static void uploadMultipartFile(MultipartFile file,String bucketName,String objectName)
            throws IOException, NoSuchAlgorithmException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, InvalidBucketNameException, XmlParserException, ErrorResponseException {
        PutObjectOptions putObjectOptions = new PutObjectOptions(file.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
        putObjectOptions.setContentType(file.getContentType());
        minioClient.putObject(bucketName,objectName,file.getInputStream(),putObjectOptions);
    }

    /**
     * Description 通过InputSteam上传
     * @param inputStream
     * @param bucketName 存储桶名称
     * @param objectName 上传到minio的文件名
     */
    public static void uploadFileByInputStream(InputStream inputStream,Long fileSize,String bucketName,String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        PutObjectOptions putObjectOptions = new PutObjectOptions(fileSize, PutObjectOptions.MIN_MULTIPART_SIZE);
        minioClient.putObject(bucketName,objectName,inputStream,putObjectOptions);
    }

    /**
     * Description 根据桶名和前缀（即文件夹名）查询文件
     * @param bucketName
     * @param prefix
     * @return List<FileTest>
     */
    public static List<FileTest> listFiles(String bucketName,String prefix) throws XmlParserException, NoSuchAlgorithmException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, InvalidBucketNameException, ErrorResponseException, IOException {
        Iterable<Result<Item>> minioObjects=minioClient.listObjects(bucketName,prefix);
        List<FileTest> fileList=new ArrayList<>();
        for(Result<Item> result:minioObjects){
            Item item=result.get();
            FileTest fileTest=new FileTest();
            fileTest.setFilename(item.objectName().substring(prefix.length()+1));
            //设置大小显示
            DecimalFormat df=new DecimalFormat("#.00");
            if (item.size()>=1024*1024*1024){
                double size=item.size()/(1024.0*1024.0*1024.0);
                fileTest.setFilesize(df.format(size)+"GB");
            }else if(item.size()>=1024*1024){
                double size=item.size()/(1024.0*1024.0);
                fileTest.setFilesize(df.format(size)+"MB");
            }else if(item.size()>=1024){
                double size=item.size()/(1024.0);
                fileTest.setFilesize(df.format(size)+"KB");
            }else {
                fileTest.setFilesize(item.size()+"B");
            }
            DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneId.of("Asia/Shanghai"));
            fileTest.setLastModifiedTime(item.lastModified().format(dtf));

            fileList.add(fileTest);
        }
        return fileList;
    }

    /**
     * Description 复制文件
     * @param bucketName 存放复制文件的存储桶
     * @param objectName 复制文件名称
     * @param srcBucketName 源文件所在桶
     * @param srcObjectName 源文件名称
     */
    public static void copyFile(String bucketName,String objectName,String srcBucketName,String srcObjectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        minioClient.copyObject(bucketName,objectName,null,null,srcBucketName,srcObjectName,null,null);
    }

    /**
     * Description 删除指定文件
     * @param bucketName
     * @param objectName
     */
    public static void deleteFile(String bucketName,String objectName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        minioClient.removeObject(bucketName,objectName);

    }

    /**
     * Description 批量删除指定前缀的文件
     * @param bucketName
     * @param prefix
     */
    public static void deleteFilesByPrefix(String bucketName,String prefix) throws XmlParserException, NoSuchAlgorithmException, InsufficientDataException, InternalException, InvalidResponseException, InvalidKeyException, InvalidBucketNameException, ErrorResponseException, IOException {
        Iterable<Result<Item>> minioObjects=minioClient.listObjects(bucketName,prefix);
        for(Result<Item> result:minioObjects){
            Item item=result.get();
            minioClient.removeObject(bucketName,item.objectName());
        }
    }

    /**
     * Description:显示存储桶中根路径下的所有文件，上面有一个listFiles方法，但如果文件直接存在存储桶中，会把首字母截掉，所以要用这个方法
     * @param bucketName
     * @return
     */
    public static List<FileTest> listBucketFiles(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
        Iterable<Result<Item>> minioObjects=minioClient.listObjects(bucketName);
        List<FileTest> fileList=new ArrayList<>();
        for(Result<Item> result:minioObjects){
            Item item=result.get();
            FileTest fileTest=new FileTest();
            fileTest.setFilename(item.objectName());
            //设置大小显示
            DecimalFormat df=new DecimalFormat("#.00");
            if (item.size()>=1024*1024*1024){
                double size=item.size()/(1024.0*1024.0*1024.0);
                fileTest.setFilesize(df.format(size)+"GB");
            }else if(item.size()>=1024*1024){
                double size=item.size()/(1024.0*1024.0);
                fileTest.setFilesize(df.format(size)+"MB");
            }else if(item.size()>=1024){
                double size=item.size()/(1024.0);
                fileTest.setFilesize(df.format(size)+"KB");
            }else {
                fileTest.setFilesize(item.size()+"B");
            }
            DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneId.of("Asia/Shanghai"));
            fileTest.setLastModifiedTime(item.lastModified().format(dtf));

            fileList.add(fileTest);
        }
        return fileList;
    }




}
