package com.railway.common.utils.file;

import com.railway.common.config.RailwayConfig;
import com.railway.common.exception.file.FileNameLengthLimitExceededException;
import com.railway.common.exception.file.FileSizeLimitExceededException;
import com.railway.common.exception.file.InvalidExtensionException;
import com.railway.common.utils.DateUtils;
import com.railway.common.utils.StringUtils;
import com.railway.common.utils.uuid.IdUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

/**
 * 文件上传工具类
 *
 * @author railway
 */
@Slf4j
public class FileUploadUtils {

  /**
   * 默认大小 50M
   */
  public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

  /**
   * 默认的文件名最大长度 100
   */
  public static final int DEFAULT_FILE_NAME_LENGTH = 100;

  public static MultipartFile upload(File localFile){
    FileItemFactory factory = new DiskFileItemFactory(16, null);
    FileItem fileItem = factory.createItem("textField", "text/plain", true, localFile.getName());
    int bytesRead;
    byte[] buffer = new byte[8192];
    try {
      FileInputStream fis = new FileInputStream(localFile);
      OutputStream os = fileItem.getOutputStream();
      while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
        os.write(buffer, 0, bytesRead);
      }
      os.close();
      fis.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return new CommonsMultipartFile(fileItem);
  }

  /**
   * 根据文件路径上传
   *
   * @param baseDir 相对应用的基目录
   * @param file 上传的文件
   * @return 文件名称
   */
  public static String upload(String baseDir, MultipartFile file) throws IOException {
    try {
      return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
    } catch (Exception e) {
      throw new IOException(e.getMessage(), e);
    }
  }

  /**
   * 文件上传
   *
   * @param baseDir 相对应用的基目录
   * @param file 上传的文件
   * @param allowedExtension 上传文件类型
   * @return 返回上传成功的文件名
   * @throws FileSizeLimitExceededException 如果超出最大大小
   * @throws FileNameLengthLimitExceededException 文件名太长
   * @throws IOException 比如读写文件出错时
   * @throws InvalidExtensionException 文件校验异常
   */
  public static String upload(String baseDir, MultipartFile file, String[] allowedExtension)
      throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
      InvalidExtensionException {
    int fileNamelength = file.getOriginalFilename().length();
    if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
      throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
    }

    assertAllowed(file, allowedExtension);

    String fileName = extractFilename(file);

    File desc = getAbsoluteFile(baseDir, fileName);
    file.transferTo(desc);
    return getPathFileName(fileName);
  }

  /**
   * 编码文件名
   */
  public static String extractFilename(MultipartFile file) {
    String fileName = file.getOriginalFilename();
    log.info("OriginalFilename : {}", fileName);
    String extension = getExtension(file);
    fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
    return fileName;
  }

  public static File getAbsoluteFile(String uploadDir, String fileName) {
    File desc = new File(uploadDir + File.separator + fileName);
    if (!desc.exists()) {
      if (!desc.getParentFile().exists()) {
        desc.getParentFile().mkdirs();
      }
    }
    return desc;
  }

  /**
   * 获取下载路径
   *
   * @param filename 文件名称
   */
  public static String getAbsoluteFile(String filename) {
    getAbsoluteFile(RailwayConfig.getFilePath(), filename);
    return RailwayConfig.getFilePath() + File.separator + filename;
  }

  public static String getPathFileName(String fileName) {
    return "/" + fileName;
  }

  /**
   * 文件大小校验
   *
   * @param file 上传的文件
   * @throws FileSizeLimitExceededException 如果超出最大大小
   */
  public static void assertAllowed(MultipartFile file, String[] allowedExtension)
      throws FileSizeLimitExceededException, InvalidExtensionException {
    long size = file.getSize();
    if (size > DEFAULT_MAX_SIZE) {
      throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
    }

    String fileName = file.getOriginalFilename();
    String extension = getExtension(file);
    if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
      if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
        throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension,
            extension,
            fileName);
      } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
        throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension,
            extension,
            fileName);
      } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
        throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension,
            extension,
            fileName);
      } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
        throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension,
            extension,
            fileName);
      } else {
        throw new InvalidExtensionException(allowedExtension, extension, fileName);
      }
    }
  }

  /**
   * 判断MIME类型是否是允许的MIME类型
   */
  public static boolean isAllowedExtension(String extension, String[] allowedExtension) {
    for (String str : allowedExtension) {
      if (str.equalsIgnoreCase(extension)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 获取文件名的后缀
   *
   * @param file 表单文件
   * @return 后缀名
   */
  public static String getExtension(MultipartFile file) {
    String extension = FilenameUtils.getExtension(file.getOriginalFilename());
    if (StringUtils.isEmpty(extension)) {
      extension = MimeTypeUtils.getExtension(file.getContentType());
    }
    return extension;
  }
}