package com.njcn.oss.utils;

import cn.hutool.core.text.CharPool;
import cn.hutool.core.text.StrPool;
import com.njcn.common.config.GeneralInfo;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.huawei.obs.util.OBSUtil;
import com.njcn.minioss.bo.MinIoUploadResDTO;
import com.njcn.minioss.config.MinIossProperties;
import com.njcn.minioss.util.MinIoUtils;
import com.njcn.oss.constant.GeneralConstant;
import com.njcn.oss.enums.OssResponseEnum;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Optional;
import java.util.UUID;

/**
 * @author hongawen
 * @version 1.0.0
 * @date 2023年03月07日 22:24
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FileStorageUtil {

    @Resource
    private MinioClient instance;

    private final GeneralInfo generalInfo;

    /***
     * 华为文件服务器工具类
     * 若有方法需求或方法不满足，去私有仓库下载huawei-obs-springboot-starter模块进行二次开发
     * 开发完毕后需deploy到maven私有仓库
     */
    private final OBSUtil obsUtil;

    /***
     * 免费开源Minioss文件服务器工具类
     * 若有方法需求或方法不满足，去私有仓库下载minioss-springboot-starter模块进行二次开发
     * 开发完毕后需deploy到maven私有仓库
     */
    private final MinIoUtils minIoUtils;

    private final MinIossProperties minIossProperties;


    /***
     * 上传MultipartFile文件，
     * @author hongawen
     * @date 2023/3/7 22:48
     * @param multipartFile  文件源
     * @param dir 服务器文件存放路径
     */
    public String uploadMultipart(MultipartFile multipartFile, String dir) {
        String filePath;
        if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
            filePath = dir + minIoUtils.minFileName(multipartFile.getOriginalFilename());
            obsUtil.uploadMultipart(multipartFile, filePath);
        } else {
            try {
                //把名称存入数据
                MinIoUploadResDTO minIoUploadResDTO = minIoUtils.upload(multipartFile, minIossProperties.getBucket(), dir);
                filePath = minIoUploadResDTO.getMinFileName();
            } catch (Exception e) {
                throw new BusinessException(OssResponseEnum.UPLOAD_FILE_ERROR);
            }
        }
        return filePath;
    }

    /***
     * 上传InputStream流，
     * @author hongawen
     * @date 2023/3/7 22:48
     * @param inputStream  文件源
     * @param dir 服务器文件存放路径
     * @param fileName 原始文件名
     */
    public String uploadStream(InputStream inputStream, String dir, String fileName) {
        String filePath;
        if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
            filePath = dir + minIoUtils.minFileName(fileName);
            obsUtil.uploadStream(inputStream, filePath);
        } else {
            try {
                //把名称存入数据
                MinIoUploadResDTO minIoUploadResDTO = minIoUtils.uploadStream(inputStream, minIossProperties.getBucket(), dir, minIoUtils.minFileName(fileName));
                filePath = minIoUploadResDTO.getMinFileName();
            } catch (Exception e) {
                throw new BusinessException(OssResponseEnum.UPLOAD_FILE_ERROR);
            }
        }
        return filePath;
    }

    /**
     * 上传InputStream流,并指定文件的名称
     * @author xuyang
     * @param inputStream
     * @param dir
     * @param fileName
     * @return
     */
    public String uploadStreamSpecifyName(InputStream inputStream, String dir, String fileName) {
        String filePath;
        if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
            filePath = dir + minIoUtils.minFileName(fileName);
            obsUtil.uploadStream(inputStream, filePath);
        } else {
            try {
                //把名称存入数据
                MinIoUploadResDTO minIoUploadResDTO = uploadStreamSpecifyName(inputStream, minIossProperties.getBucket(), dir, fileName);
                filePath = minIoUploadResDTO.getMinFileName();
            } catch (Exception e) {
                throw new BusinessException(OssResponseEnum.UPLOAD_FILE_ERROR);
            }
        }
        return filePath;
    }


    /***
     * 根据文件路径获取文件短期的一个url
     * @author hongawen
     * @date 2023/3/7 23:04
     * @param filePath 文件在服务器的路径
     */
    public String getFileUrl(String filePath) {
        String url;
        if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
            url = obsUtil.getFileUrl(filePath);
        } else {
            url = minIoUtils.getObjectUrl(minIossProperties.getBucket(), filePath, 7 * 24 * 60 * 60);
        }
        return url;
    }


    /***
     * 根据文件路径获取文件流
     * @author hongawen
     * @date 2023/3/7 23:04
     * @param filePath 文件在服务器的路径
     */
    public InputStream getFileStream(String filePath) {
        InputStream inputStream;
        try {
            if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
                inputStream = obsUtil.downloadStream(filePath);
            } else {
                inputStream = minIoUtils.downloadStream(minIossProperties.getBucket(), filePath);
            }
        } catch (Exception exception) {
            throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
        }
        return inputStream;
    }

    /***
     * 根据文件路径获取文件流并下载
     * @author hongawen
     * @date 2023/3/7 23:04
     * @param filePath 文件在服务器的路径
     */
    public void downloadStream(HttpServletResponse response, String filePath) {
        InputStream inputStream;
        OutputStream toClient = null;
        try {
            if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
                inputStream = obsUtil.downloadStream(filePath);
            } else {
                inputStream = minIoUtils.downloadStream(minIossProperties.getBucket(), filePath);
            }
        } catch (Exception exception) {
            throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
        }
        String fileType = filePath.substring(filePath.lastIndexOf('.')).toLowerCase();
        switch (fileType) {
            case "jpg":
            case "jpeg":
            case "png":
            case "gif":
                response.setContentType(MediaType.IMAGE_PNG_VALUE);
                break;
            case "pdf":
                response.setContentType("application/pdf");
                response.setHeader("Content-Disposition", "attachment;filename=" + filePath);
                break;
            default:
                response.setContentType("application/octet-stream;charset=UTF-8");
                response.setHeader("Content-Disposition", "attachment;filename=" + filePath);
                break;
        }
        try {
            toClient = new BufferedOutputStream(response.getOutputStream());
            //通过IOUtils对接输入输出流，实现文件下载
            IOUtils.copy(inputStream, toClient);
            toClient.flush();
        } catch (Exception e) {
            throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
        } finally {
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(toClient);
        }

    }

    /**
     * 获取下载文件流
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public InputStream downloadStream(String filePath) {
        InputStream inputStream;
        try {
            if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
                inputStream = obsUtil.downloadStream(filePath);
            } else {
                inputStream = minIoUtils.downloadStream(minIossProperties.getBucket(), filePath);
            }
        } catch (Exception exception) {
            throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
        }
        return inputStream;
    }

    /***
     * 根据文件路径删除指定文件对象
     * @author hongawen
     * @date 2023/3/8 9:25
     * @param fileName  文件路径名
     */
    public void deleteFile(String fileName) {
        if (generalInfo.getBusinessFileStorage() == GeneralConstant.HUAWEI_OBS) {
            obsUtil.delete(fileName);
        } else {
            minIoUtils.removeObject(minIossProperties.getBucket(), fileName);
        }
    }

    public MinIoUploadResDTO uploadStreamSpecifyName(InputStream inputStream, String bucketName, String directory, String fileName) throws Exception {
        if (!minIoUtils.bucketExists(bucketName)) {
            minIoUtils.makeBucket(bucketName);
        }
        directory = (String) Optional.ofNullable(directory).orElse("");
        String minFileName = directory + fileName;
        this.instance.putObject((PutObjectArgs)((io.minio.PutObjectArgs.Builder)((io.minio.PutObjectArgs.Builder)PutObjectArgs.builder().bucket(bucketName)).object(minFileName)).stream(inputStream, (long)inputStream.available(), -1L).build());
        inputStream.close();
        return new MinIoUploadResDTO(minFileName, minIoUtils.getObjectUrl(bucketName, minFileName, 60));
    }

}
