package org.jeecg.modules.minio.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.http.Method;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.minio.config.MinIoProperties;
import org.jeecg.modules.minio.dto.UploadFileParamDTO;
import org.simpleframework.xml.core.Validate;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * @author WangPeng
 * @date 2022/12/30 11:26
 * @description
 */
@Slf4j
@Api(tags = "Minio客户端文件管理")
@RestController
@RequestMapping("/sys/minio/file")
public class MinIoFileController {

    @Resource
    private MinioClient minioClient;

    @Resource
    private MinIoProperties minIoProperties;

    /**
     * Minio文件上传
     *
     * @param fileParam 文件上传参数
     * @return 上传文件地址
     */
    @ApiOperation("Minio文件上传")
    @PostMapping(value = "/upload")
    public Result<?> upload(@Validate UploadFileParamDTO fileParam){
        //获取原始文件名称
        try (InputStream inputStream = fileParam.getFile().getInputStream()) {
            MultipartFile file = fileParam.getFile();
            String filePath = getFilePath(fileParam.getBiz(), file.getOriginalFilename());
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(minIoProperties.getBucketName())
                            .object(filePath)
                            .stream(inputStream, file.getSize(), -1)
                            .contentType(MediaTypeFactory.getMediaType(file.getOriginalFilename()).orElse(MediaType.APPLICATION_OCTET_STREAM).toString())
                            .build());
            return Result.OK(minIoProperties.getMappingPath() + StrUtil.SLASH + minIoProperties.getBucketName() + filePath);
        }catch (Exception e) {
            log.error("---Minio文件上传失败。", e);
            throw new JeecgBootException("---Minio文件上传失败。");
        }
    }

    /**
     * Minio文件上传
     *
     * @param fileParam 文件上传参数
     * @return 上传文件地址
     */
    @ApiOperation("Minio字节文件上传")
    @PostMapping(value = "/upload-byte")
    public Result<?> uploadByte(@RequestBody @Validate UploadByteParamDTO fileParam) {
        //获取原始文件名称
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(fileParam.getFile())) {
            byte[] fileByte = fileParam.getFile();
            String filePath = getFilePath(fileParam.getBiz(), fileParam.getFileName());
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(minIoProperties.getBucketName())
                            .object(filePath)
                            .stream(inputStream, fileByte.length, -1)
                            .contentType(MediaTypeFactory.getMediaType(fileParam.getFileName()).orElse(MediaType.APPLICATION_OCTET_STREAM).toString())
                            .build());
            return Result.OK(minIoProperties.getMappingPath() + StrUtil.SLASH + minIoProperties.getBucketName() + filePath);
        } catch (Exception e) {
            log.error("---Minio文件上传失败。", e);
            throw new JeecgBootException("---Minio文件上传失败。");
        }
    }

    /***
     * 删除Minio文件
     */
    @ApiOperation("Minio文件删除")
    @DeleteMapping(value = "/delete")
    public Result<?> removeObject(@RequestParam String filePath) throws Exception {
        filePath = filePath.replace(minIoProperties.getMappingPath() + StrUtil.SLASH + minIoProperties.getBucketName(), "");
        minioClient.removeObject(RemoveObjectArgs.builder().bucket(minIoProperties.getBucketName()).object(filePath).build());
        return Result.OK();
    }

    /**
     * Minio文件签名地址
     *
     * @param filePath 文件路径
     */
    @GetMapping(value = "/signed-address")
    public void getSignedAddress(@RequestParam String filePath, HttpServletResponse response) throws Exception {
        filePath = filePath.replace(minIoProperties.getMappingPath() + StrUtil.SLASH + minIoProperties.getBucketName(), "");
        String url = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(minIoProperties.getBucketName())
                        .object(filePath)
                        .expiry(2, TimeUnit.HOURS)
                        .build());
        response.sendRedirect(url);
    }

    /**
     * 获取文件路径
     *
     * @param bizPath 模块名称
     * @param orgName 文件名称
     * @return 文件对象路径
     */
    private static String getFilePath(String bizPath, String orgName) {
        Assert.notNull(orgName, "文件名称不能为空。");
        String fileName = IdUtil.fastUUID();
        String filenameExtension = StringUtils.getFilenameExtension(orgName);
        //文件原始名称+毫秒数+随机6位+文件类型
        fileName = fileName + StrUtil.DASHED + System.currentTimeMillis() + StrUtil.DOT + filenameExtension;
        String module = StrUtil.EMPTY;
        if (StrUtil.isNotBlank(bizPath)) {
            module = StrUtil.SLASH + bizPath;
        }
        return module + productionFolder() + fileName;
    }

    /**
     * 每天生成文件夹 /yyyy-MM/
     *
     * @return 文件路径
     */
    public static String productionFolder() {
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM");
        LocalDate now = LocalDate.now();
        return StrUtil.SLASH + now.format(pattern) + StrUtil.SLASH;
    }
}
