package com.zhentao.utils;

import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * MinIO工具类
 * 用于上传、下载、删除文件等操作
 */
@Component
@Slf4j
public class MinioUtil {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.proofBucketName:Proof-of-success}")
    private String proofBucketName;

    /**
     * 初始化，检查并创建bucket
     */
    @PostConstruct
    public void init() {
        try {
            createBucketIfNotExists();
            log.info("✅ MinIO初始化成功，Bucket: {}", bucketName);
        } catch (Exception e) {
            log.error("❌ MinIO初始化失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 检查bucket是否存在，不存在则创建
     */
    private void createBucketIfNotExists() throws Exception {
        boolean exists = minioClient.bucketExists(
                BucketExistsArgs.builder()
                        .bucket(bucketName)
                        .build()
        );

        if (!exists) {
            minioClient.makeBucket(
                    MakeBucketArgs.builder()
                            .bucket(bucketName)
                            .build()
            );
            log.info("✅ 创建Bucket成功: {}", bucketName);
        }
    }

    /**
     * 上传文件（字节数组）
     *
     * @param fileBytes 文件字节数组
     * @param fileName  文件名
     * @param contentType 文件类型
     * @return 文件访问URL
     */
    public String uploadFile(byte[] fileBytes, String fileName, String contentType) throws Exception {
        try (InputStream inputStream = new ByteArrayInputStream(fileBytes)) {
            return uploadFile(inputStream, fileName, contentType, fileBytes.length);
        }
    }

    /**
     * 上传文件（输入流）
     *
     * @param inputStream 文件输入流
     * @param fileName    文件名
     * @param contentType 文件类型
     * @param fileSize    文件大小
     * @return 文件访问URL
     */
    public String uploadFile(InputStream inputStream, String fileName, String contentType, long fileSize) throws Exception {
        // 生成唯一文件名
        String objectName = generateUniqueFileName(fileName);

        // 上传文件
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, fileSize, -1)
                        .contentType(contentType)
                        .build()
        );

        log.info("✅ 文件上传成功: {}", objectName);

        // 返回文件访问URL
        return getFileUrl(objectName);
    }

    /**
     * 上传语音文件
     *
     * @param fileBytes 语音文件字节数组
     * @param originalFileName 原始文件名
     * @return 文件访问URL
     */
    public String uploadVoiceFile(byte[] fileBytes, String originalFileName) throws Exception {
        String contentType = getContentType(originalFileName);
        return uploadFile(fileBytes, originalFileName, contentType);
    }

    /**
     * 获取文件URL（永久访问）
     *
     * @param objectName 对象名称
     * @return 文件访问URL
     */
    public String getFileUrl(String objectName) {
        // 返回完整的访问路径
        return String.format("%s/%s/%s", endpoint, bucketName, objectName);
    }

    /**
     * 获取预签名URL（临时访问，7天有效）
     *
     * @param objectName 对象名称
     * @return 预签名URL
     */
    public String getPresignedUrl(String objectName) throws Exception {
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(7, TimeUnit.DAYS)
                        .build()
        );
    }

    /**
     * 删除文件
     *
     * @param objectName 对象名称
     */
    public void deleteFile(String objectName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()
        );
        log.info("✅ 文件删除成功: {}", objectName);
    }

    /**
     * 根据URL删除文件
     *
     * @param fileUrl 文件URL
     */
    public void deleteFileByUrl(String fileUrl) throws Exception {
        String objectName = extractObjectNameFromUrl(fileUrl);
        deleteFile(objectName);
    }

    /**
     * 从URL中提取对象名称
     *
     * @param fileUrl 文件URL
     * @return 对象名称
     */
    private String extractObjectNameFromUrl(String fileUrl) {
        // 格式: http://115.190.125.125:9000/minion-voice-files/voice/xxx.mp3
        String prefix = String.format("%s/%s/", endpoint, bucketName);
        if (fileUrl.startsWith(prefix)) {
            return fileUrl.substring(prefix.length());
        }
        return fileUrl;
    }

    /**
     * 生成唯一文件名
     *
     * @param originalFileName 原始文件名
     * @return 唯一文件名
     */
    private String generateUniqueFileName(String originalFileName) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String extension = getFileExtension(originalFileName);
        String dateFolder = new java.text.SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date());
        return String.format("voice/%s/%s%s", dateFolder, uuid, extension);
    }

    /**
     * 获取文件扩展名
     *
     * @param fileName 文件名
     * @return 扩展名（包含点号）
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 根据文件名获取Content-Type
     *
     * @param fileName 文件名
     * @return Content-Type
     */
    private String getContentType(String fileName) {
        String extension = getFileExtension(fileName).toLowerCase();
        switch (extension) {
            case ".mp3":
                return "audio/mpeg";
            case ".wav":
                return "audio/wav";
            case ".ogg":
                return "audio/ogg";
            case ".m4a":
                return "audio/mp4";
            case ".amr":
                return "audio/amr";
            case ".aac":
                return "audio/aac";
            default:
                return "application/octet-stream";
        }
    }

    /**
     * 检查文件是否存在
     *
     * @param objectName 对象名称
     * @return 是否存在
     */
    public boolean fileExists(String objectName) {
        try {
            minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 上传文件到成功凭证桶（Proof-of-success）
     *
     * @param fileBytes 文件字节数组
     * @param fileName  文件名
     * @param contentType 文件类型
     * @return 文件访问URL
     */
    public String uploadFileToProofBucket(byte[] fileBytes, String fileName, String contentType) throws Exception {
        // 确保桶存在
        createBucketIfNotExists(proofBucketName);
        
        try (java.io.InputStream inputStream = new java.io.ByteArrayInputStream(fileBytes)) {
            // 生成唯一文件名
            String objectName = generateProofFileName(fileName);
            
            // 上传文件
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(proofBucketName)
                            .object(objectName)
                            .stream(inputStream, fileBytes.length, -1)
                            .contentType(contentType)
                            .build()
            );
            
            log.info("✅ 成功凭证图片上传成功: bucket={}, object={}", proofBucketName, objectName);
            
            // 返回文件访问URL
            return String.format("%s/%s/%s", endpoint, proofBucketName, objectName);
        }
    }

    /**
     * 检查并创建指定的bucket
     */
    private void createBucketIfNotExists(String targetBucket) throws Exception {
        boolean exists = minioClient.bucketExists(
                BucketExistsArgs.builder()
                        .bucket(targetBucket)
                        .build()
        );

        if (!exists) {
            minioClient.makeBucket(
                    MakeBucketArgs.builder()
                            .bucket(targetBucket)
                            .build()
            );
            log.info("✅ 创建Bucket成功: {}", targetBucket);
        }
    }

    /**
     * 生成成功凭证文件名
     *
     * @param originalFileName 原始文件名
     * @return 唯一文件名
     */
    private String generateProofFileName(String originalFileName) {
        String uuid = java.util.UUID.randomUUID().toString().replace("-", "");
        String extension = getFileExtension(originalFileName);
        String dateFolder = new java.text.SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date());
        return String.format("proof/%s/%s%s", dateFolder, uuid, extension);
    }
}
