package com.xueyi.file.service;

import com.xueyi.file.config.MinioConfig;
import com.xueyi.file.utils.FileUploadUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.messages.Retention;
import io.minio.messages.RetentionMode;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.ZonedDateTime;

/**
 * Minio 文件存储
 *
 * @author xueyi
 */
@Primary
@Service
public class MinioSysFileServiceImpl implements ISysFileService {

    private static final Logger log = LoggerFactory.getLogger(MinioSysFileServiceImpl.class);
    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient client;

    /**
     * 本地文件上传接口
     *
     * @param file 上传的文件
     * @return 访问地址
     */
    @Override
    public String uploadFile(MultipartFile file) throws Exception {
        String fileName = FileUploadUtils.extractFilename(file);

        //fileName = URLEncoder.encode(fileName, "UTF-8");
        log.info("Minio filename: {}" , fileName);
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        log.info("Minio 文件上传成功");
        // 获取fileName的最后一个'/'的位置的字符串，并用URLEncoder进行UTF-8编码后，再拼接到fileName中
        String splitStr = fileName.substring(fileName.lastIndexOf("/") + 1);
        splitStr = URLEncoder.encode(splitStr, "UTF-8");
        fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr;
        return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
    }

    @Override
    public String uploadExactFile(MultipartFile file, String extension) throws Exception {
        String fileName = FileUploadUtils.extractFilename(file);

        fileName += extension;
        //fileName = URLEncoder.encode(fileName, "UTF-8");
        log.info("Minio filename: {}" , fileName);
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build();
        client.putObject(args);
        log.info("Minio 文件上传成功");
        // 获取fileName的最后一个'/'的位置的字符串，并用URLEncoder进行UTF-8编码后，再拼接到fileName中
        String splitStr = fileName.substring(fileName.lastIndexOf("/") + 1);
        splitStr = URLEncoder.encode(splitStr, "UTF-8");
        fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr;
        return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
    }

    @Override
    public String uploadTempFile(MultipartFile file) throws Exception {
        return null;
    }

    @Override
    public String uploadFile(String fileName, File file) throws Exception {
        fileName = FileUploadUtils.extractFilename(fileName);
        InputStream inputStream = FileUtils.openInputStream(file);
        log.info("file original filename = {}" , fileName);
        log.info("file size = {} " , file.length());

        // 使用IOUtils.toByteArray()方法确保正确地读取输入流中的数据
        byte[] fileBytes = IOUtils.toByteArray(inputStream);

        // 上传文件到MinIO
        String minioFileName = uploadFileToMinIO(fileName, fileBytes);

        log.info("MinIO 文件上传成功，Minio 文件名：{}" , minioFileName);

        // 获取fileName的最后一个'/'的位置的字符串，并用URLEncoder进行UTF-8编码后，再拼接到fileName中
        String splitStr = fileName.substring(fileName.lastIndexOf("/") + 1);
        splitStr = URLEncoder.encode(splitStr, "UTF-8");
        fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr;

        return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
    }


    public String uploadTempFile(String fileName, File file) throws Exception {
        fileName = FileUploadUtils.extractFilename(fileName);
        InputStream inputStream = FileUtils.openInputStream(file);
        log.info("file original filename = {} " , fileName);
        log.info("file size = {}" , file.length());

        // 使用IOUtils.toByteArray()方法确保正确地读取输入流中的数据
        byte[] fileBytes = IOUtils.toByteArray(inputStream);

        // 上传文件到MinIO
        String minioFileName = uploadFileToMinIO(fileName, fileBytes);

        log.info("MinIO Temp文件上传成功，Minio 文件名：{}", minioFileName);

        // 获取fileName的最后一个'/'的位置的字符串，并用URLEncoder进行UTF-8编码后，再拼接到fileName中
        String splitStr = fileName.substring(fileName.lastIndexOf("/") + 1);
        splitStr = URLEncoder.encode(splitStr, "UTF-8");
        fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr;

        return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
    }

    // 上传文件到MinIO
    private String uploadFileToMinIO(String fileName, byte[] fileBytes) throws Exception {
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(minioConfig.getBucketName())
                .object(fileName)
                .stream(new ByteArrayInputStream(fileBytes), fileBytes.length, -1)
                .contentType("application/octet-stream")
                .build();
        client.putObject(args);
        return fileName;
    }


    public String uploadFile(File file) throws Exception {
        String  fileName = file.getName();
        // 获取fileName的最后一个'/'的位置的字符串，并用URLEncoder进行UTF-8编码后，再拼接到fileName中
        // 使用PutObjectArgs上传文件到MinIO
        ZonedDateTime end = ZonedDateTime.now().plusDays(90); // Set the end time to 90 days from now
        client.putObject(
                PutObjectArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(fileName)
                        .stream(new FileInputStream(file), file.length(), -1)
                        .contentType("application/octet-stream")
                        .retention(new Retention(RetentionMode.COMPLIANCE, end))
                        .build()
        );

        log.info("文件上传到MinIO成功：{}", fileName);
        String splitStr = fileName.substring(fileName.lastIndexOf("/") + 1);
        splitStr = URLEncoder.encode(splitStr, "UTF-8");
        fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1) + splitStr;
        return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
    }



    /**
     * 文件删除接口，通过minio的文件url进行删除
     *
     * @param url 文件url
     * @return 结果
     */
    public Boolean deleteFile(String url) throws Exception {
        String bucketName = minioConfig.getBucketName();
        String fileName = url.substring(url.indexOf(bucketName) + bucketName.length() + 1);
        client.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build());
        return true;
    }
}
