package com.cwhelp.component.fileUpload;

import com.cwhelp.common.exception.ResultException;
import com.cwhelp.common.utils.SpringContextUtil;
import com.cwhelp.common.utils.ToolUtil;
import com.cwhelp.component.fileUpload.config.properties.UploadProjectProperties;
import com.cwhelp.component.fileUpload.enums.UploadResultEnum;
import com.cwhelp.modules.system.domain.Upload;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 文件上传处理工具
 * @author yan.y
 */
public class FileUpload {

    /**
     * 创建一个Upload实体对象
     * @param multipartFile MultipartFile对象
     * @param modulePath 文件模块路径
     */
    public static Upload getFile(MultipartFile multipartFile, String modulePath){
        if (multipartFile.getSize() == 0){
            throw new ResultException(UploadResultEnum.NO_FILE_NULL);
        }
        Upload upload = new Upload();
        upload.setMime(multipartFile.getContentType());
        upload.setSize(multipartFile.getSize());
        upload.setName(FileUpload.genFileName(multipartFile.getOriginalFilename()));
        upload.setPath(getPathPattern() + modulePath + FileUpload.genDateMkdir("yyyyMMdd") + upload.getName());
        return upload;
    }

    /**
     * 判断文件是否为支持的格式
     * @param multipartFile MultipartFile对象
     * @param types 支持的文件类型数组
     */
    public static boolean isContentType(MultipartFile multipartFile, String[] types){
        List<String> typeList = Arrays.asList(types);
        return typeList.contains(multipartFile.getContentType());
    }

    /**
     * 获取文件上传保存路径
     */
    public static String getUploadPath(){
        UploadProjectProperties properties = SpringContextUtil.getBean(UploadProjectProperties.class);
        return properties.getFilePath();
    }

    /**
     * 获取文件上传目录的静态资源路径
     */
    public static String getPathPattern(){
        UploadProjectProperties properties = SpringContextUtil.getBean(UploadProjectProperties.class);
        return properties.getStaticPath().replace("/**", "");
    }

    /**
     * 生成随机且唯一的文件名
     */
    public static String genFileName(String originalFilename){
        String fileSuffix = ToolUtil.getFileSuffix(originalFilename);
        return UUID.randomUUID().toString().replace("-", "") + fileSuffix;
    }

    /**
     * 生成指定格式的目录名称(日期格式)
     */
    public static String genDateMkdir(String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return "/" + sdf.format(new Date()) + "/";
    }

    /**
     * 获取目标文件对象
     * @param upload 上传实体类
     */
    public static File getDestFile(Upload upload) throws IOException {

        // 创建保存文件对象
        String path = upload.getPath().replace(getPathPattern(), "");
        String filePath = getUploadPath() + path;
        File dest = new File(filePath.replace("//", "/"));
        if(!dest.exists()){
            dest.getParentFile().mkdirs();
            dest.createNewFile();
        }

        return dest;
    }

    /**
     * 保存文件及获取文件MD5值和SHA1值
     * @param multipartFile MultipartFile对象
     * @param upload Upload
     */
    public static void transferTo(MultipartFile multipartFile, Upload upload) throws IOException, NoSuchAlgorithmException {

        byte[] buffer = new byte[4096];
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        MessageDigest sha1 = MessageDigest.getInstance("SHA1");
        try (OutputStream fos = Files.newOutputStream(getDestFile(upload).toPath()); InputStream fis = multipartFile.getInputStream()) {
            int len = 0;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
                md5.update(buffer, 0, len);
                sha1.update(buffer, 0, len);
            }
            fos.flush();
        }
        BigInteger MD5Bi = new BigInteger(1, md5.digest());
        BigInteger SHA1Bi = new BigInteger(1, sha1.digest());
        upload.setMd5(MD5Bi.toString(16));
        upload.setSha1(SHA1Bi.toString(16));
    }

    /**
     * 获取文件的SHA1值
     */
    public static String getFileSHA1(MultipartFile multipartFile) {
        if (multipartFile.getSize() == 0){
            throw new ResultException(UploadResultEnum.NO_FILE_NULL);
        }
        byte[] buffer = new byte[4096];
        try (InputStream fis = multipartFile.getInputStream()) {
            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
            int len = 0;
            while ((len = fis.read(buffer)) != -1) {
                sha1.update(buffer, 0, len);
            }
            BigInteger SHA1Bi = new BigInteger(1, sha1.digest());
            return SHA1Bi.toString(16);
        } catch (IOException | NoSuchAlgorithmException e) {
            return null;
        }
    }

}
