package com.heyu.api.oss;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.heyu.api.data.constants.MimeTypeEnums;
import com.heyu.api.data.utils.ConfigProperties;
import com.heyu.api.data.utils.DateUtils;
import com.heyu.api.data.utils.DigestUtil;
import com.heyu.api.data.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.*;

/**
 * 类OssFileUploadServiceImpl.java的实现描述：oss上传文件类
 *
 * @author richen 2015年12月1日 下午6:11:49
 */
@Service
@Slf4j
public class OssFileUploadServiceImpl implements OssFileUploadService {

    private static Logger log = LoggerFactory.getLogger(OssFileUploadServiceImpl.class);

    public static String env = "prd";

    private String oss_buccket = "heyuimage";

    private String oss_url = "https://heyuimage.ihzhy.com/";


    static {
        env = "prd/" + DateUtils.formatDate(new Date(), "yyyyMM");
    }


    @Resource
    private OSSClient ossClient;

    @Override
    public OssUploadResult uploadToOss(MultipartFile imageFile) {
        String fileName = imageFile.getOriginalFilename();
        String contextType = this.getImageFileContentType(fileName);
        String path = env + "/" ;
        String fileNameSuffix = DigestUtil.MD5_16(UUID.randomUUID().toString());
        if (StringUtils.isNotBlank(contextType)) {
            fileNameSuffix = fileNameSuffix + fileName.substring(fileName.lastIndexOf("."));
        }
        return this.uploadFileToOss(imageFile, contextType, path, fileNameSuffix);
    }



    @Override
    public List<Map<String, Object>> uploadImages(MultipartFile[] files) {
        List<Map<String,Object>> result = new ArrayList<>();
        for(MultipartFile file: files){
            log.info("uploadImage filename = " + file.getOriginalFilename() + ",fileSize=" + file.getSize());

            String url;
            Map<String,Object> data = new HashMap<>(2);
            OssUploadResult uploadResult = uploadImageToOss(file);
            if(uploadResult.isSuccess()){
                url =  uploadResult.getUrl();
                data.put("srcFileName", file.getOriginalFilename());
                data.put("url", url);
            }else{
                data.put("srcFileName", file.getOriginalFilename());
                data.put("url", "");
            }
            result.add(data);
        }
        return result;
    }


    @Override
    public OssUploadResult uploadImageToOss(MultipartFile imageFile) {
        String fileName = imageFile.getOriginalFilename();
        String contextType = this.getImageFileContentType(fileName);
        if (StringUtils.isBlank(contextType)) {
            contextType = "image/jpeg";
        }
        String path = env + "/";
        String fileNameSuffix = DigestUtil.MD5_16(UUID.randomUUID().toString());
        if (StringUtils.isNotBlank(contextType)) {
            fileNameSuffix = fileNameSuffix + fileName.substring(fileName.lastIndexOf("."));
        }
        return this.uploadFileToOss(imageFile, contextType, path, fileNameSuffix);
    }




    @Override
    public OssUploadResult uploadImageByBytes(byte[] bytes) {
        InputStream inputStream = null;
        OssUploadResult result = new OssUploadResult();
        try {

            String suffix = ".jpeg";
            // 步骤 2: 使用字节数组创建 InputStream
            inputStream = new ByteArrayInputStream(bytes);
            // 生成文件名称
            String path = env + "/";

            String fileName = DigestUtil.MD5_16(UUID.randomUUID().toString()) + suffix;

            //3 获取文件信息，为了上传
            // meta设置请求头
            ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType(MimeTypeEnums.getContentType(suffix));
            //4 设置知道文件夹
            PutObjectResult pubResult = ossClient.putObject(oss_buccket, path + fileName, inputStream, meta);

            result.setSuccess(true);
            result.setMsg("upload to oss succeed");
            result.setFileMd5(pubResult.getETag());
            result.setUrl(oss_url + path + fileName);
            return result;
        } catch (Exception e) {
            log.error("upload to oss error", e);
        } finally {
            if(inputStream !=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("inputStream  to close error", e);
                }
            }
        }
        return null;
    }



    @Override
    public OssUploadResult uploadImageToOss(InputStream inputStream, String fileName, int fileSize) {
        OssUploadResult result = new OssUploadResult();
        try {
            String path = env + "/";
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileSize);
            metadata.setContentType(this.getImageFileContentType(fileName));
            PutObjectResult pubResult = ossClient.putObject(oss_buccket, path + fileName, inputStream, metadata);

            if (pubResult == null || StringUtils.isBlank(pubResult.getETag())) {
                log.error("upload to oss error, put object result is null or etag is empty,  fileName {}", fileName);
                result.setSuccess(false);
                result.setMsg("upload to oss error, put object result is null or etag is empty");
                return result;
            }
            result.setSuccess(true);
            result.setMsg("upload inputStream to oss succeed");
            result.setFileMd5(pubResult.getETag());
            result.setUrl(oss_url + path + fileName);
        } catch (Exception e) {
            log.error("upload inputStream to oss error", e);
            result.setSuccess(false);
            result.setMsg("upload inputStream to oss error, message is " + e.getMessage());
        }
        return result;
    }


    @Override
    public OssUploadResult uploadImageToOss(InputStream inputStream,String buccket, String fileName, int fileSize) {
        OssUploadResult result = new OssUploadResult();
        try {
            String path = env + "/";
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileSize);
            metadata.setContentType(this.getImageFileContentType(fileName));
            PutObjectResult pubResult = ossClient.putObject(buccket, path + fileName, inputStream, metadata);

            if (pubResult == null || StringUtils.isBlank(pubResult.getETag())) {
                log.error("upload to oss error, put object result is null or etag is empty,  fileName {}", fileName);
                result.setSuccess(false);
                result.setMsg("upload to oss error, put object result is null or etag is empty");
                return result;
            }
            result.setSuccess(true);
            result.setMsg("upload inputStream to oss succeed");
            result.setFileMd5(pubResult.getETag());
            result.setUrl(oss_url + path + fileName);
        } catch (Exception e) {
            log.error("upload inputStream to oss error", e);
            result.setSuccess(false);
            result.setMsg("upload inputStream to oss error, message is " + e.getMessage());
        }
        return result;
    }





    @Override
    public OssUploadResult uploadImageToOssAsync(InputStream inputStream, String fileName, int fileSize) {
        return this.uploadImageToOss(inputStream, fileName, fileSize);
    }

    /**
     * @param file        文件
     * @param contextType 文件类型
     * @param path        路径
     * @return
     */
    private OssUploadResult uploadFileToOss(MultipartFile file, String contextType, String path, String fileName) {
        OssUploadResult result = new OssUploadResult();
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.getSize());
        metadata.setContentType(contextType);
        try {
            PutObjectResult pubResult = ossClient.putObject(oss_buccket, path + fileName, file.getInputStream(), metadata);
            if (pubResult == null || StringUtils.isBlank(pubResult.getETag())) {
                log.error("upload to oss error, put object result is null or etag is empty,  fileName {}", fileName);
                result.setSuccess(false);
                result.setMsg("upload to oss error, put object result is null or etag is empty");
                return result;
            }
            result.setSuccess(true);
            result.setMsg("upload to oss succeed");
            result.setFileMd5(pubResult.getETag());
            result.setUrl(oss_url + path + fileName);
        } catch (Exception e) {
            log.error("upload to oss error", e);
            result.setSuccess(false);
            result.setMsg("upload to oss error, message is " + e.getMessage());
        }
        return result;
    }


    @Override
    public void uploadUploadFile(File file, String path) throws Exception {
        ossClient.putObject(oss_buccket, "h5/" + path, file);
    }

    @Override
    public String uploadFileContentByBase64(String base64EncodedString,String suffix) {
        InputStream inputStream = null;
        try {
            // 步骤 1: 解码 Base64 字符串为字节数组
            byte[] decodedBytes = Base64.getDecoder().decode(base64EncodedString);
            // 步骤 2: 使用字节数组创建 InputStream
            inputStream = new ByteArrayInputStream(decodedBytes);
            String bucketName = ConfigProperties.get("oss.config.bucketName");
            String endpoint = ConfigProperties.get("oss.config.endpoint");
            // 生成文件名称
            String nameSuffix = "test/" + UUID.randomUUID().toString() + "." + suffix;
            //3 获取文件信息，为了上传
            // meta设置请求头
            ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType(MimeTypeEnums.getContentType(suffix));
            //4 设置知道文件夹
            ossClient.putObject(bucketName, nameSuffix, inputStream, meta);
            //6 返回上传之后地址，拼接地址
            String uploadUrl = "https://" + bucketName + "." + endpoint + "/test/" + nameSuffix;
            log.info("upload to oss succeed :{}", uploadUrl);
        } catch (Exception e) {
            log.error("upload to oss error", e);
        }finally {
            if(inputStream !=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("inputStream  to close error", e);
                }
            }
        }
        return null;
    }

    public static String getImageFileContentType(String fileName) {
        if (StringUtils.isBlank(fileName) || fileName.indexOf(".") < 0) {
            return "";
        }
        String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        if ("jpeg".equals(fileSuffix) || "jpg".equals(fileSuffix)) {
            return "image/jpeg";
        } else if ("png".equals(fileSuffix)) {
            return "image/png";
        } else if ("bmp".equals(fileSuffix)) {
            return "image/bmp";
        } else if ("pdf".equals(fileSuffix)) {
            return "application/pdf";
        }
        return "";
    }


    /**
     * 上传PDF文件
     *
     * @param file       文件
     * @param remotePath 外网路径
     * @return
     * @throws Exception
     */
    @Override
    public String uploadPdfFile(File file, String remotePath) throws Exception {
        InputStream fileContent = null;
        fileContent = new FileInputStream(file);
        String path = env + "/";
        String remoteFilePath = remotePath.substring(0, remotePath.length()).replaceAll("\\\\", "/") + "/";
        // 创建上传Object的Metadata
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(fileContent.available());
        objectMetadata.setHeader("x-oss-server-side-encryption", "AES256");
        objectMetadata.setContentType("application/pdf");
        // 上传文件
        objectMetadata.setContentType(getImageFileContentType(file.getName()));
        PutObjectResult putObject = ossClient.putObject(oss_buccket, path + remoteFilePath + file.getName(), fileContent, objectMetadata);
        if (putObject == null) {
            log.error("upload to oss error, put object result is null or etag is empty,  fileName {}");
            return null;
        }
        log.info(file.getName() + " upload file to osss ...");
        try {
            if (fileContent != null) {
                fileContent.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return oss_url + path + remoteFilePath + file.getName();
    }


    /**
     * 上传PDF文件（文件流）
     *
     * @param inputStream 文件流
     * @param fileName    文件名
     * @param remotePath  上传地址
     * @return 文件外网地址
     * @throws Exception
     */
    @Override
    public String uploadPdfFile(InputStream inputStream, String fileName, String remotePath) throws Exception {

        String path = env + "/";
        String remoteFilePath = remotePath.substring(0,
                remotePath.length()).replaceAll("\\\\", "/") + "/";
        // 创建上传Object的Metadata
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(inputStream.available());
        objectMetadata.setHeader("x-oss-server-side-encryption", "AES256");
        // 上传文件
        objectMetadata.setContentType(getImageFileContentType(fileName));
        PutObjectResult putObject = ossClient.putObject(oss_buccket,
                path + remoteFilePath + fileName, inputStream, objectMetadata);
        if (putObject == null) {
            log.error("upload to oss error, put object result is null or etag is empty,  fileName {}");
            return null;
        }
        log.info(fileName + " upload file to osss ...");
        try {
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return oss_url + path + remoteFilePath + fileName;
    }

}
