package com.yice.common.minio.util;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.BooleanUtil;
import com.yice.common.core.upload.UpDownloaderFactory;
import com.yice.common.core.upload.UploadResponseInfo;
import com.yice.common.core.upload.BaseUpDownloader;
import com.yice.common.core.upload.UploadStoreTypeEnum;
import com.yice.common.core.util.MyCommonUtil;
import com.yice.common.minio.wrapper.MinioTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * 基于Minio上传和下载文件操作的工具类。
 *
 * @author linking
 * @date 2023-04-13
 */
@Slf4j
@Component
@ConditionalOnProperty(prefix = "minio", name = "enabled")
public class MinioUpDownloader extends BaseUpDownloader {

    @Autowired
    private MinioTemplate minioTemplate;
    @Autowired
    private UpDownloaderFactory factory;

    @PostConstruct
    public void doRegister() {
        factory.registerUpDownloader(UploadStoreTypeEnum.MINIO_SYSTEM, this);
    }

    @Override
    public UploadResponseInfo doUpload(
            String serviceContextPath,
            String rootBaseDir,
            String modelName,
            String fieldName,
            Boolean asImage,
            MultipartFile uploadFile) throws IOException {
        UploadResponseInfo responseInfo = super.verifyUploadArgument(asImage, uploadFile);
        if (BooleanUtil.isTrue(responseInfo.getUploadFailed())) {
            return responseInfo;
        }
        String uploadPath = super.makeFullPath(null, modelName, fieldName, asImage);
        responseInfo.setUploadPath(uploadPath);
        super.fillUploadResponseInfo(responseInfo, serviceContextPath, uploadFile.getOriginalFilename());
        minioTemplate.putObject(uploadPath + "/" + responseInfo.getFilename(), uploadFile.getInputStream());
        return responseInfo;
    }

    @Override
    public void doDownload(
            String rootBaseDir,
            String modelName,
            String fieldName,
            String fileName,
            Boolean asImage,
            HttpServletResponse response) throws IOException {
        String uploadPath = this.makeFullPath(null, modelName, fieldName, asImage);
        String fullFileanme = uploadPath + "/" + fileName;
        this.downloadInternal(fullFileanme, fileName, response);
    }

    @Override
    public void doDownload(
            String rootBaseDir,
            String uriPath,
            String fileName,
            HttpServletResponse response) throws IOException {
        StringBuilder pathBuilder = new StringBuilder(128);
        String fullFileanme = pathBuilder.append(uriPath).append("/").append(fileName).toString();
        this.downloadInternal(fullFileanme, fileName, response);
    }

    /**
     * 方法重置写入Minio里面中，保留文件名称
     * 执行文件上传操作，将文件数据存入Minio。
     *
     * @param inputStream         上传地址。
     * @param fileName         文件名称。
     * @return 上传应答信息对象。该对象始终不为null。
     * @throws IOException minio抛出的异常。
     */
    @Override
    public UploadResponseInfo doUpload(InputStream inputStream, String fileName){
        UploadResponseInfo responseInfo = new UploadResponseInfo();
        StringBuilder filenameBuilder = new StringBuilder(64);
        filenameBuilder.append(MyCommonUtil.generateUuid())
                .append(".").append(FilenameUtils.getExtension(fileName));
        responseInfo.setFilename(filenameBuilder.toString());
        minioTemplate.putObject(responseInfo.getFilename(), inputStream);
        return responseInfo;
    }

    private void downloadInternal(String fullFileanme, String fileName, HttpServletResponse response) throws IOException {
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        InputStream in = minioTemplate.getStream(fullFileanme);
        IoUtil.copy(in, response.getOutputStream());
        in.close();
    }
}
