package com.seer.teach.common.minio.service;

import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.exception.FileUploadException;
import com.seer.teach.common.minio.config.MinioConfig;
import com.seer.teach.common.utils.CommonUtils;
import io.minio.MinioClient;
import io.minio.GetObjectArgs;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * @Author: Captain
 * @Description: MinIO上传Service
 * @Date: 2025-05-19 14:21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MinioService {


    private final MinioClient minioClient;

    /**
     * Author: Captain
     * Desc:   上传文件
     * Params: [folderPrefix, fileName, inputStream, contentType]
     * Return: void
     * Time: 2025/5/19 14:25
     */
    public void upload(String folderPrefix, String fileName, InputStream inputStream, String contentType) {
        upload(MinioConfig.BUCKET, folderPrefix, fileName, inputStream, contentType);
    }

    public void upload(String bucketName,String folder, String fileName, InputStream inputStream, String contentType) {
        try {
            String objectName = folder + "/" + fileName;
            log.info("MinIO upload file: {}，bucketName ： {}", objectName,bucketName);
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(inputStream, -1, 10 * 1024 * 1024) // 设置合理的part size为10MB
                            .contentType(contentType)
                            .build()
            );
            log.info("MinIO upload file success: {}", objectName);
        } catch (Exception e) {
            log.error("Minio上传失败: {}", e.getMessage(), e);
            throw new FileUploadException(ResultCodeEnum.FILE_UPLOAD_ERROR);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                    log.info("close inputStream success");
                } catch (IOException e) {
                    log.warn("Failed to close input stream", e);
                }
            }
        }
    }

    /**
     * Author: Captain
     * Desc:   删除文件
     * Params: [folderPrefix, fileName]
     * Return: void
     * Time: 2025/5/20
     */
    public void delete(String objectName) throws Exception {
        log.info("MinIO delete file: {}", objectName);
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(MinioConfig.BUCKET)
                        .object(objectName)
                        .build()
        );
        log.info("MinIO delete file success: {}", objectName);
    }

    /**
     * Author: Captain
     * Desc:   多文件上传
     * Params: [folderPrefix, files]
     * Return: List<String> 上传成功的文件URL列表
     * Time: 2025/7/13
     */
    public void uploadMultipleFiles(String folderPrefix, MultipartFile[] files) throws IOException {
        for (MultipartFile file : files) {
            if (file.isEmpty()) {
                continue;
            }
            upload(folderPrefix, file.getOriginalFilename(), file.getInputStream(), file.getContentType());
        }
    }

    /**
     * 上传音频封装方法
     */
    public String uploadAudio(Integer childrenId, byte[] audioData, String contentType) {
        try {
            String fileName = CommonUtils.generateWavFileName(childrenId);
            try (InputStream inputStream = new ByteArrayInputStream(audioData)) {
                this.upload(MinioConfig.AI_AUDIO_FOlDER, fileName, inputStream, contentType);
            }
            return fileName;
        } catch (Exception e) {
            throw new FileUploadException(ResultCodeEnum.AUDIO_UPLOAD_FAILED);
        }
    }

    /**
     * 上传健康知识音频封装方法
     */
    public String uploadHealthArticledAudio(Integer childrenId, byte[] audioData, String contentType) {
        try {
            String fileName = CommonUtils.generateWavFileName(childrenId);
            try (InputStream inputStream = new ByteArrayInputStream(audioData)) {
                this.upload(MinioConfig.AI_HEALTH_ARTICLE_AUDIO, fileName, inputStream, contentType);
            }
            return fileName;
        } catch (Exception e) {
            throw new FileUploadException(ResultCodeEnum.AUDIO_UPLOAD_FAILED);
        }
    }

    /**
     * 上传Chat音频封装方法
     */
    public String uploadChatAudio(Integer childrenId, byte[] audioData, String contentType) {
        try {
            String fileName = CommonUtils.generateWavFileName(childrenId);
            try (InputStream inputStream = new ByteArrayInputStream(audioData)) {
                this.upload(MinioConfig.AI_CHAT_AUDIO, fileName, inputStream, contentType);
            }
            return fileName;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new FileUploadException(ResultCodeEnum.AUDIO_UPLOAD_FAILED);
        }
    }

    /**
     * 上传Smart音频封装方法
     */
    public String uploadSmartAudio(Integer childrenId, byte[] audioData, String contentType) {
        try {
            String fileName = CommonUtils.generateWavFileName(childrenId);
            try (InputStream inputStream = new ByteArrayInputStream(audioData)) {
                this.upload(MinioConfig.AI_SMART_AUDIO, fileName, inputStream, contentType);
            }
            return fileName;
        } catch (Exception e) {
            throw new FileUploadException(ResultCodeEnum.AUDIO_UPLOAD_FAILED);
        }
    }

    /**
     * 上传Smart音频封装方法
     */
    public String uploadPreviewAudio(Integer childrenId, byte[] audioData, String contentType) {
        try {
            String fileName = CommonUtils.generateWavFileName(childrenId);
            try (InputStream inputStream = new ByteArrayInputStream(audioData)) {
                this.upload(MinioConfig.AI_PREVIEW_AUDIO, fileName, inputStream, contentType);
            }
            return fileName;
        } catch (Exception e) {
            throw new FileUploadException(ResultCodeEnum.AUDIO_UPLOAD_FAILED);
        }
    }

    /**
     * 上传Smart音频封装方法
     */
    public String uploadReviewAudio(Integer childrenId, byte[] audioData, String contentType) {
        try {
            String fileName = CommonUtils.generateWavFileName(childrenId);
            try (InputStream inputStream = new ByteArrayInputStream(audioData)) {
                this.upload(MinioConfig.AI_PREVIEW_AUDIO, fileName, inputStream, contentType);
            }
            return fileName;
        } catch (Exception e) {
            throw new FileUploadException(ResultCodeEnum.AUDIO_UPLOAD_FAILED);
        }
    }

    /**
     * 删除音频封装方法
     */
    public void deleteAudio(String fileName) {
        try {
            this.delete(MinioConfig.AI_AUDIO_FOlDER + fileName);
        } catch (Exception e) {
            log.warn("删除音频失败，fileName={}", fileName, e);
        }
    }

    /**
     * 删除 MinIO 中的对象
     *
     * @param bucket   存储桶名称
     * @param fileName 对象名称（包含文件夹路径，例如 avatar/xxx.png）
     */
    public void remove(String bucket, String fileName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucket)
                        .object(fileName)
                        .build()
        );
    }
    
    /**
     * 从MinIO下载文件
     *
     * @param bucketName 存储桶名称
     * @param objectName 对象名称（包含文件夹路径）
     * @return 文件输入流
     * @throws Exception 可能抛出的异常
     */
    public InputStream download(String bucketName, String objectName) throws Exception {
        log.info("开始从MinIO下载文件: bucket={}, object={}", bucketName, objectName);
        try {
            InputStream inputStream = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );
            log.info("MinIO文件下载成功: bucket={}, object={}", bucketName, objectName);
            return inputStream;
        } catch (Exception e) {
            log.error("MinIO文件下载失败: bucket={}, object={}, error={}", bucketName, objectName, e.getMessage(), e);
            throw e;
        }
    }
    
    /**
     * 从MinIO下载文件
     *
     * @param objectName 对象名称（包含文件夹路径）
     * @return 文件输入流
     * @throws Exception 可能抛出的异常
     */
    public InputStream download(String objectName) throws Exception {
        return download(MinioConfig.BUCKET, objectName);
    }
}

