package com.css.simulation.resource.scheduler.infra.fs.minio;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class MinioUtil {

    /**
     * 删除文件夹
     *
     * @param bucketName bucket名称
     * @param prefix     文件夹全路径
     * @since tarzan LIU
     */
    @SneakyThrows
    public static void rmR(MinioClient minioClient, String bucketName, String prefix) {
        Iterable<Result<Item>> list = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName)
                .prefix(prefix).recursive(true).build());
        if (list == null || !list.iterator().hasNext()) {
            log.info(prefix + " 不存在。");
            return;
        }
        for (Result<Item> object : list) {
            rm(minioClient, bucketName, object.get().objectName());
        }
        log.info("rmR() 删除 minio 目录 " + bucketName + "/" + prefix + "完成。");
    }

    // 获取所有文件，过滤调文件夹
    @SneakyThrows
    public static List<String> listAllFileName(MinioClient minioClient, String bucketName, String prefix) {
        Iterable<Result<Item>> list = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName)
            .prefix(prefix).recursive(true).build());
        if (list == null || !list.iterator().hasNext()) {
            log.info(prefix + " 不存在。");
            return new ArrayList<>();
        }
        List<String> res = new ArrayList<>();
        for (Result<Item> object : list) {
            if (object.get().isDir()){
                continue;
            }
            String name = object.get().objectName();
            res.add(name);
        }
        return res;
    }

    /**
     * 删除文件
     *
     * @param minioClient minio 客户端对象
     * @param bucket      桶
     * @param object      文件对象
     */
    @SneakyThrows
    public static void rm(MinioClient minioClient, String bucket, String object) {
        minioClient.removeObject(RemoveObjectArgs.builder()
                .bucket(bucket)
                .object(object)
                .build());
    }

    /**
     * 判断 bucket 是否存在
     */
    public static boolean isBucketExist(MinioClient minioClient, String bucketName) throws InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 判断 object 是否存在
     */
    public static boolean isObjectExist(MinioClient minioClient, String bucket, String object) {
        try {
            StatObjectResponse objectStat = minioClient.statObject(StatObjectArgs.builder().bucket(bucket).object(object).build());
            return objectStat != null;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 创建 bucket
     */
    public static void createBucket(MinioClient minioClient, String bucketName) throws InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
        if (!isBucketExist(minioClient, bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 获取预览路径
     *
     * @return 预览路径
     */
    public static String getPreviewUrl(MinioClient minioClient, Method method, String bucket, String object) throws io.minio.errors.ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, io.minio.errors.InternalException {
        return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                .method(method)
                .bucket(bucket)
                .object(object)
                .build());
    }

    /**
     * 通过文件路径上传文件上传文件
     */
    public static void uploadFromFile(
            MinioClient minioClient,
            String sourceFilePath,
            String bucketName,
            String objectName
    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
        minioClient.uploadObject(UploadObjectArgs.builder()
                .filename(sourceFilePath)
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 通过文件路径上传文件上传文件
     *
     * @param partSize 分片最小 5MB
     */
    public static void uploadFromStream(
            MinioClient minioClient,
            InputStream inputStream,
            long objectSize,
            long partSize,
            String bucketName,
            String objectName
    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
        minioClient.putObject(PutObjectArgs.builder()
                .stream(inputStream, objectSize, partSize)
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 通过文件路径上传文件上传文件
     */
    public static void uploadFromMultipartFile(
            MinioClient minioClient,
            MultipartFile multipartFile,
            String bucketName,
            String objectName
    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
        InputStream inputStream = multipartFile.getInputStream();
        long objectSize = multipartFile.getSize();
//        long partSize = 5 * 1024 * 1024L; // 分片最小 5M
        long partSize = -1; // 不分片
        minioClient.putObject(PutObjectArgs.builder()
                .stream(inputStream, objectSize, partSize)
                .bucket(bucketName)
                .object(objectName)
                .build());
    }


    /**
     * 下载文件
     */
    @SneakyThrows
    public static void downloadToFile(MinioClient minioClient, String bucket, String object, String targetFilePath) {
        File file = new File(targetFilePath);
        if (!file.getParentFile().exists()) {
            boolean mkdir = file.getParentFile().mkdirs();
        }
        boolean objectExist = isObjectExist(minioClient, bucket, object);
        if (objectExist) {
            minioClient.downloadObject(DownloadObjectArgs.builder()
                    .bucket(bucket)
                    .object(object)
                    .filename(targetFilePath)
                    .build());
        } else {
            throw new RuntimeException("downloadToFile() minio 文件" + object + "不存在。");
        }
    }

    /**
     * 下载文件
     */
    public static InputStream downloadToStream(
            MinioClient minioClient,
            String bucketName,
            String objectName
    ) throws IOException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, io.minio.errors.ServerException, io.minio.errors.InternalException {
        return minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    /**
     * 读取文件内容
     */
    public static String downloadToString(
            MinioClient minioClient,
            String bucketName,
            String objectName
    ) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, io.minio.errors.InternalException {
        GetObjectResponse response = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
        StringBuilder result = new StringBuilder();
        byte[] buf = new byte[4096];//创建字节数组，存储临时读取的数据
        int len;//记录数据读取的长度
        //循环读取数据
        while ((len = response.read(buf)) != -1) { //长度为-1则读取完毕
            result.append(new String(buf, 0, len)).append("\n");
        }
        response.close();
        return result.toString();
    }
}
