package com.bohuikeji.frame.module.admin.utils;

import com.bohuikeji.frame.module.admin.component.StaticComponent;
import com.netease.cloud.services.nos.NosClient;
import com.netease.cloud.services.nos.model.NOSObject;
import io.minio.MinioClient;
import io.minio.errors.*;
import io.minio.policy.PolicyType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.xmlpull.v1.XmlPullParserException;

import javax.imageio.ImageIO;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.util.Random;
import java.util.StringJoiner;

import static org.omg.CORBA.ORB.init;

/**
 * 对象存储工具类
 * @author 10552
 */
public final class MinioUtil {
    private static final Logger log = LoggerFactory.getLogger(MinioUtil.class);
    /**
     * 认证
     */
    private final transient static String ACCESS_KEY="minio";
    private final transient static String SECRET_KEY="BH_Minio1024";
    /**
     * 桶名称（使用项目名称）
     */
    private final transient static String BUCKET_NAME= StaticComponent.applicationName;
    /**
     * 下载服务器
     */
    private final transient static String OSS_URL_READ="https://oss.tcjskd.com/";
    /**
     * 上传服务器
     */
    private final transient static String OOS_URL_WRITE=StaticComponent.OOS_WRITE_URL;
    /**
     * 桶是否存在的逻辑标志
     */
    private transient static boolean BUCKET_EXISTS=false;

    public static void uploadFiles(String filePath) {
    }

    /**
     * 内部类实现单例
     * 对MinioClient只初始化一次
     */
    private static class MinioClientHolder {
        private static  MinioClient minioClient;
        static {
            try {
                minioClient = new MinioClient(OOS_URL_WRITE,ACCESS_KEY, SECRET_KEY);
            } catch (InvalidEndpointException e) {
                log.error("OOS初始化错误：[{}]",e);
                e.printStackTrace();
            } catch (InvalidPortException e) {
                log.error("OOS初始化错误：[{}]",e);
                e.printStackTrace();
            }
        }
    }
    /**
     * 获取minio客户端实例
     * @return
     */
    private static MinioClient getMinioClient(){
        return MinioClientHolder.minioClient;
    }

    /**
     * 上传文件
     * 支持单文件，多文件
     * 返回文件访问路径，多文件以分号‘；’分隔
     * @param muFiles
     * @return
     */
    public static String uploadFiles(MultipartFile... muFiles) {
        if (muFiles.length<1){
            throw new RuntimeException("上传文件为空！");
        }
        StringJoiner joiner=new StringJoiner(";");
        for (MultipartFile muFile : muFiles) {
            joiner.add(uploadFile(muFile));
        }
        return joiner.toString();

    }
    /**
     * 内部方法
     * 上传文件
     * @return
     */
    public static String uploadFile(InputStream inputStream,String pix){
        log.info("当前上传桶名称：[{}]",StaticComponent.applicationName);
        String fileName="/"+FileUtil.getPathName()+pix;
        try {
            MinioClient minioClient = getMinioClient();
            if(!BUCKET_EXISTS&&!minioClient.bucketExists(BUCKET_NAME)){
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS=true;
            }

            minioClient.putObject(BUCKET_NAME,fileName, inputStream,"application/octet-stream");
        }  catch (Exception e) {
            log.error("文件上传失败",e);
            throw new RuntimeException("文件上传失败");
        }
        return OSS_URL_READ+BUCKET_NAME+fileName;
    }

    /**
     * 内部方法
     * 上传文件
     * @param muFile
     * @return
     */
    public static String uploadFileB(InputStream inputStream,String pix){
        log.info("当前上传桶名称：[{}]",StaticComponent.applicationName);
        String fileName="/"+MinioUtil.getPathName(pix,false);
        try {
            MinioClient minioClient = getMinioClient();
            if(!BUCKET_EXISTS&&!minioClient.bucketExists(BUCKET_NAME)){
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS=true;
            }

            minioClient.putObject(BUCKET_NAME,fileName, inputStream,"image/jpeg");
        }  catch (Exception e) {
            log.error("文件上传失败",e);
            throw new RuntimeException("文件上传失败");
        }
        return OSS_URL_READ+BUCKET_NAME+fileName;
    }

    /**
     * 下载文件-
     * 【注意】该方法仅支持由本系统上传的文件下载
     * @param url
     * @return
     */
    public static InputStream downloadFile(String url){
       /* if (url.indexOf(OSS_URL_READ)<0){
            log.error("该文件不是由本项目上传，不适应该方法下载！");
            log.error("错误的下载地址：[{}]",url);
            throw new RuntimeException("该文件不是由本项目上传，不适应该方法下载！");
        }*/
        MinioClient minioClient = getMinioClient();
        InputStream inputStream;
        try {
            inputStream=minioClient.getObject(BUCKET_NAME,url.substring((OSS_URL_READ+BUCKET_NAME).length()),url.length()-1);
        } catch (Exception e) {
            log.error("对象存储服务异常，位于：",e);
            throw new RuntimeException("对象存储服务异常，请联系管理员处理！");
        }
        return inputStream;
    }


    /**
     * 内部方法
     * 上传文件
     * @param muFile
     * @return
     */
    private static String uploadFile(MultipartFile muFile){
        log.info("当前上传桶名称：[{}]",StaticComponent.applicationName);
        String fileName = FileUtil.getFilePathName(muFile,true);
        try {
            MinioClient minioClient = getMinioClient();
            if(!BUCKET_EXISTS&&!minioClient.bucketExists(BUCKET_NAME)){
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS=true;
            }
            InputStream inputStream=muFile.getInputStream();
            //如果是图片文件就进行压缩
            if (ImageUtil.isImage(muFile)){
                inputStream=ImageUtil.getInputStream(
                        ImageUtil.setWatermark(
                                ImageUtil.compress(
                                        ImageIO.read(inputStream))),
                        ImageUtil.getFileExtention(muFile.getOriginalFilename()));
            }
            minioClient.putObject(BUCKET_NAME, fileName , inputStream,muFile.getContentType());
        }  catch (Exception e) {
            log.error("文件上传失败",e);
            throw new RuntimeException("文件上传失败");
        }
        return OSS_URL_READ+BUCKET_NAME+fileName;
    }

    public static String getPathName(String pathName,boolean isRetain){
        String fileName = pathName;
        String name=fileName;
        String prefix="";
        if(fileName.indexOf('.')!=-1) {
            name=fileName.substring(0,fileName.indexOf('.'));
            prefix=fileName.substring(fileName.lastIndexOf("."));
        }

        LocalDate date = LocalDate.now();
        StringBuilder filePathName=new StringBuilder("/upload/");
        filePathName.append(date.getYear());
        filePathName.append("/");
        filePathName.append(date.getMonthValue());
        filePathName.append("/");
        filePathName.append(date.getDayOfMonth());
        filePathName.append("/");
        Random r = new Random();
        int pix=r.ints(1, (100 + 1)).findFirst().getAsInt();
        filePathName.append(System.currentTimeMillis());
        filePathName.append(""+pix);
        //文件名超过64字符则截取
        if(isRetain){
            filePathName.append("_");
            if(name.length()>64){
                name=name.substring(0,64);
            }
            filePathName.append(name);
        }
        filePathName.append(prefix);
        return filePathName.toString();
    }


    /**
     * 内部方法
     * 上传文件
     * @param muFile
     * @return
     */
    /*public static String uploadFileC(InputStream inputStream,String pix,String name){
        log.info("当前上传桶名称：[{}]",StaticComponent.applicationName);
        String fileName="/"+MinioUtil.getQianPathName(pix,false);
        try {
            MinioClient minioClient = getMinioClient();
            if(!BUCKET_EXISTS&&!minioClient.bucketExists(BUCKET_NAME)){
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS=true;
            }
            //如果是图片文件就进行压缩
            *//*if (pix.equals(".jpg")){
                inputStream=ImageUtil.getInputStream(
                        ImageUtil.setWatermark(
                                ImageUtil.compress(
                                        ImageIO.read(inputStream))),
                        ImageUtil.getFileExtention(name));
            }*//*
            minioClient.putObject(BUCKET_NAME,fileName, inputStream,"image/jpeg");
        }  catch (Exception e) {
            log.error("文件上传失败",e);
            throw new RuntimeException("文件上传失败");
        }
        return OSS_URL_READ+BUCKET_NAME+fileName;
    }*/

    /**
     * 数据迁移上传
     * @param muFiles
     * @return
     */
    public static String dataUploadFiles(String folder, MultipartFile... muFiles) {
        if (muFiles.length<1){
            throw new RuntimeException("上传文件为空！");
        }
        StringJoiner joiner=new StringJoiner(";");
        for (MultipartFile muFile : muFiles) {
            joiner.add(dataUploadFile(muFile,folder));
        }
        return joiner.toString();

    }

    /**
     * 内部方法
     * 迁移数据上传文件
     * @param muFile
     * @return
     */
    private static String dataUploadFile(MultipartFile muFile,String folder){
        log.info("当前上传桶名称：[{}]",StaticComponent.applicationName);
        String fileName = MinioUtil.getQianPathName(muFile,true,folder);
        try {
            MinioClient minioClient = getMinioClient();
            if(!BUCKET_EXISTS&&!minioClient.bucketExists(BUCKET_NAME)){
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS=true;
            }
            InputStream inputStream=muFile.getInputStream();
            //如果是图片文件就进行压缩
            if (ImageUtil.isImage(muFile)){
                inputStream=ImageUtil.getInputStream(
                        ImageUtil.setWatermark(
                                ImageUtil.compress(
                                        ImageIO.read(inputStream))),
                        ImageUtil.getFileExtention(muFile.getOriginalFilename()));
            }
            minioClient.putObject(BUCKET_NAME, fileName , inputStream,muFile.getContentType());
        }  catch (Exception e) {
            log.error("文件上传失败",e);
            throw new RuntimeException("文件上传失败");
        }
        return OSS_URL_READ+BUCKET_NAME+fileName;
    }

    /**
     * 	 获取文件名
     * @param muFile 文件
     * @param isRetain 是否保留源文件名
     * @return 返回文件名，以当前年月日作为前缀路径
     */
    public static String getQianPathName(MultipartFile muFile,boolean isRetain,String folder){
        String fileName = muFile.getOriginalFilename();
        String name=fileName;
        //String prefix="";
       /* if(fileName.indexOf('.')!=-1) {
        	name=fileName.substring(0,fileName.indexOf('.'));
            prefix=fileName.substring(fileName.lastIndexOf("."));
        }*/

        LocalDate date = LocalDate.now();
        StringBuilder filePathName=new StringBuilder("/upload/");
       /* filePathName.append(date.getYear());
        filePathName.append("/");
        filePathName.append(date.getMonthValue());
        filePathName.append("/");
        filePathName.append(date.getDayOfMonth());
        filePathName.append("/");*/
        filePathName.append(folder);
        filePathName.append("/");
        Random r = new Random();
        int pix=r.ints(1, (100 + 1)).findFirst().getAsInt();
        //filePathName.append(System.currentTimeMillis());
        //filePathName.append(""+pix);
        //文件名超过64字符则截取
        if(isRetain){
           /* filePathName.append("_");
            if(name.length()>64){
                name=name.substring(0,64);
            }*/
            filePathName.append(name);
        }
        //filePathName.append(prefix);
        return filePathName.toString();
    }
}
