package org.xyzh.file.util;

import io.minio.*;
import io.minio.http.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xyzh.file.config.MinioConfig;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

/**
 * @description MinIO 工具类
 * @filename MinioUtil.java
 * @author yslg
 * @copyright yslg
 * @since 2025-12-09
 */
@Component
public class MinioUtil {
    
    private static final Logger logger = LoggerFactory.getLogger(MinioUtil.class);
    
    @Autowired
    private MinioConfig minioConfig;
    
    /**
     * 检查存储桶是否存在，如果不存在则创建
     * @param bucketName 存储桶名称
     * @return true 成功，false 失败
     */
    public boolean createBucketIfNotExists(String bucketName) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            // 检查存储桶是否存在
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder()
                    .bucket(bucketName)
                    .build());
            
            if (!exists) {
                // 创建存储桶
                minioClient.makeBucket(MakeBucketArgs.builder()
                        .bucket(bucketName)
                        .build());
                logger.info("成功创建存储桶: {}", bucketName);
            }
            
            return true;
        } catch (Exception e) {
            logger.error("创建存储桶失败: {}", bucketName, e);
            return false;
        }
    }
    
    /**
     * 上传文件到MinIO
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param inputStream 文件输入流
     * @param size 文件大小
     * @param contentType 文件类型
     * @return true 成功，false 失败
     */
    public boolean uploadFile(String bucketName, String objectName, InputStream inputStream, long size, String contentType) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            // 确保存储桶存在
            if (!createBucketIfNotExists(bucketName)) {
                return false;
            }
            
            // 上传文件
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(inputStream, size, -1)
                    .contentType(contentType)
                    .build());
            
            logger.info("文件上传成功: {}/{}", bucketName, objectName);
            return true;
            
        } catch (Exception e) {
            logger.error("文件上传失败: {}/{}", bucketName, objectName, e);
            return false;
        }
    }
    
    /**
     * 上传字节数组到MinIO
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param data 字节数组
     * @param contentType 文件类型
     * @return true 成功，false 失败
     */
    public boolean uploadFile(String bucketName, String objectName, byte[] data, String contentType) {
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(data)) {
            return uploadFile(bucketName, objectName, inputStream, data.length, contentType);
        } catch (IOException e) {
            logger.error("创建字节数组输入流失败", e);
            return false;
        }
    }
    
    /**
     * 下载文件
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @return 文件输入流，失败返回null
     */
    public InputStream downloadFile(String bucketName, String objectName) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            return minioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            
        } catch (Exception e) {
            logger.error("文件下载失败: {}/{}", bucketName, objectName, e);
            return null;
        }
    }
    
    /**
     * 删除文件
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @return true 成功，false 失败
     */
    public boolean deleteFile(String bucketName, String objectName) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            
            logger.info("文件删除成功: {}/{}", bucketName, objectName);
            return true;
            
        } catch (Exception e) {
            logger.error("文件删除失败: {}/{}", bucketName, objectName, e);
            return false;
        }
    }
    
    /**
     * 获取文件的预签名URL（用于临时访问）
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @param expiry 过期时间（秒）
     * @return 预签名URL，失败返回null
     */
    public String getPresignedUrl(String bucketName, String objectName, int expiry) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(bucketName)
                    .object(objectName)
                    .expiry(expiry, TimeUnit.SECONDS)
                    .build());
            
        } catch (Exception e) {
            logger.error("生成预签名URL失败: {}/{}", bucketName, objectName, e);
            return null;
        }
    }
    
    /**
     * 检查文件是否存在
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @return true 存在，false 不存在
     */
    public boolean fileExists(String bucketName, String objectName) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取文件信息
     * @param bucketName 存储桶名称
     * @param objectName 对象名称
     * @return 文件信息，失败返回null
     */
    public StatObjectResponse getFileInfo(String bucketName, String objectName) {
        try {
            MinioClient minioClient = minioConfig.getMinioClient();
            
            return minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            
        } catch (Exception e) {
            logger.error("获取文件信息失败: {}/{}", bucketName, objectName, e);
            return null;
        }
    }
}
