package com.shanghaichengdi.ghjgitem.util;


import com.shanghaichengdi.ghjgitem.config.SnowflakeMakeConf;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @program: ghjg-service
 * @description: 文件类
 * @author: 欧永卿
 * @create: 2021-07-08 16:28
 **/
@Slf4j
@Component
public class FileUtil {

  @Autowired
  SnowflakeMakeConf snowflakeMakeConf;

  /**
   * @param bytes    byte数组
   * @param filePath 文件路径
   * @param fileName 文件名
   * @return void
   * @Author oyq
   * @Description //TODO 将Byte数组转换成文件
   * @Date 2021/8/5 17:00
   **/
  public static File bytesToFile(byte[] bytes, String filePath, String fileName) {
    BufferedOutputStream bos = null;
    FileOutputStream fos = null;
    File file = null;
    try {

      file = new File(filePath + fileName);
      if (!file.getParentFile().exists()) {
        //文件夹不存在 生成
        file.getParentFile().mkdirs();
      }
      fos = new FileOutputStream(file);
      bos = new BufferedOutputStream(fos);
      bos.write(bytes);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (bos != null) {
        try {
          bos.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if (fos != null) {
        try {
          fos.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return file;
  }

  /**
   * 创建路径
   *
   * @Author oyq
   * @Date 2022/10/28 15:25
   **/
  public static Path crePath(String filePath) throws IOException {
    if (filePath.lastIndexOf(".") != -1) {
      String pa = filePath.substring(filePath.lastIndexOf("/"));
      filePath = filePath.replace(pa, "");
    }
    return Files.createDirectories(Paths.get(filePath));
  }

  /**
   * @param fobj 目标文件
   * @return byte[]
   * @Author oyq
   * @Description //TODO 将文件转换为字节流返回
   * @Date 2021/8/5 17:02
   **/
  public static byte[] fileToBytes(File fobj) {
    byte[] buffer = null;
    try {
      if (!fobj.exists()) {
        return null;
      }

      FileInputStream fis = new FileInputStream(fobj);
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      byte[] b = new byte[10240];
      int len = -1;
      while ((len = fis.read(b)) != -1) {
        bos.write(b, 0, len);
      }
      fis.close();
      bos.close();
      buffer = bos.toByteArray();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return buffer;
  }


  /**
   * @param path 文件路径
   * @return java.lang.String
   * @Author oyq
   * @Description //TODO 将文件转成base64字符串
   * @Date 2021/8/5 17:29
   **/
  public static String encodeBase64File(String path) throws Exception {
    File file = new File(path);
    FileInputStream inputFile = new FileInputStream(file);
    byte[] buffer = new byte[(int) file.length()];
    inputFile.read(buffer);
    inputFile.close();
    return new BASE64Encoder().encode(buffer);
  }

  /**
   * @param base64Code 目标字符
   * @param targetPath 目标路径
   * @return void
   * @Author oyq
   * @Description //TODO 将base64字符解码保存文件
   * @Date 2021/8/5 17:29
   **/
  public static File decoderBase64File(String base64Code, String targetPath) throws Exception {
    byte[] buffer = new BASE64Decoder().decodeBuffer(base64Code);
    File file = new File(targetPath);
    //如果文件不存在则创建
    if (!file.exists()) {
      try {
        file.createNewFile();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    FileOutputStream out = new FileOutputStream(targetPath);
    out.write(buffer);
    out.close();
    return new File(targetPath);
  }

  /**
   * @return void
   * @Author 欧永卿
   * @Description //TODO 下载网络文件到本地
   * @Date 16:34 2021-07-08
   * @Param [fileUrl, fileLocal]
   **/
  public static void downloadFile(String fileUrl, String fileLocal) throws Exception {
    URL url = new URL(fileUrl);
    HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
    urlCon.setConnectTimeout(6000);
    urlCon.setReadTimeout(6000);
    int code = urlCon.getResponseCode();
    if (code != HttpURLConnection.HTTP_OK) {
      throw new Exception("文件读取失败");
    }

    DataInputStream in = new DataInputStream(urlCon.getInputStream());
    DataOutputStream out = new DataOutputStream(new FileOutputStream(fileLocal));
    byte[] buffer = new byte[2048];
    int count = 0;
    while ((count = in.read(buffer)) > 0) {
      out.write(buffer, 0, count);
    }
    out.close();
    in.close();
  }


  /**
   * @return void
   * @Author 欧永卿
   * @Description //TODO 选中本地文件以流的方式发送
   * @Date 18:05 2021-07-08
   * @Param [tourl, fileUrl]
   **/
  public static String toFileio(String tourl, String fileUrl) throws IOException {
    DataInputStream in = null;
    OutputStream out = null;
    HttpURLConnection conn = null;
    InputStream ins = null;
    ByteArrayOutputStream outStream = null;
    try {
      URL url = new URL(tourl);
      conn = (HttpURLConnection) url.openConnection();
      conn.setDoOutput(true);
      conn.setUseCaches(false);
      conn.setRequestMethod("POST");
      conn.setRequestProperty("Content-Type", "text/html");
      conn.setRequestProperty("Cache-Control", "no-cache");
      conn.setRequestProperty("Charsert", "UTF-8");
      conn.connect();
      conn.setConnectTimeout(10000);
      out = conn.getOutputStream();

      File file = new File(fileUrl);
      in = new DataInputStream(new FileInputStream(file));

      int bytes = 0;
      byte[] buffer = new byte[1024];
      while ((bytes = in.read(buffer)) != -1) {
        out.write(buffer, 0, bytes);
      }
      out.flush();

      // 返回流
      if (true) {
        ins = conn.getInputStream();
        outStream = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        int count;
        while ((count = ins.read(data, 0, 1024)) != -1) {
          outStream.write(data, 0, count);
        }
      }
      if (outStream == null) {
        return null;
      }
      return outStream.toString("UTF-8");
    } catch (Exception e) {
      e.printStackTrace();
      return e.getMessage();
    } finally {
      if (in != null) {
        in.close();
      }
      if (out != null) {
        out.close();
      }
      if (ins != null) {
        ins.close();
      }
      if (outStream != null) {
        outStream.close();
      }
      if (conn != null) {
        conn.disconnect();
      }
    }
  }

  /**
   * copy文件并重命名
   *
   * @return String  -1，失败  1成功
   * @Author 欧永卿
   * @Description //TODO
   * @Date 18:39 2021-08-08
   * @Param [readfile, writeFile]
   **/
  public static String copyAndRen(String readfile, String writeFile) {
    try {
      FileInputStream input = new FileInputStream(readfile);
      FileOutputStream output = new FileOutputStream(writeFile);
      int read = input.read();
      while (read != -1) {
        output.write(read);
        read = input.read();
      }
      input.close();
      output.close();
      return "1";
    } catch (IOException e) {
      e.printStackTrace();
      return "-1";
    }
  }


  public static void copytest(String[] args) {
    String path1 = "D:/Users/rambo/Downloads/1.xlsx";//源文件
    String dir = "D:/Users/rambo/Downloads/temp/";//指定的文件夹
    String fileName = "2.xlsx";//指定的重命名
    copyAndRen(path1, dir + fileName);
  }

  /**
   * 图片镜像翻转
   *
   * @param source 原图片路径
   * @param target 翻转后图片输出路径
   */
  public static void mirrorImage(String source, String target) {
    File file;
    BufferedImage image;
    try {
      file = new File(source);
      image = ImageIO.read(file);

      int width = image.getWidth();
      int height = image.getHeight();

      for (int j = 0; j < height; j++) {
        int l = 0, r = width - 1;
        while (l < r) {
          int pl = image.getRGB(l, j);
          int pr = image.getRGB(r, j);
          image.setRGB(l, j, pr);
          image.setRGB(r, j, pl);
          l++;
          r--;
        }
      }

      file = new File(target);
      ImageIO.write(image, getSuffix(source), file);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  private static String getSuffix(String fileName) {
    return fileName.substring(fileName.lastIndexOf(".") + 1);
  }

  public static String lastName(File file) {
      if (file == null) {
          return null;
      }
    String filename = file.getName();
    // split用的是正则，所以需要用 //. 来做分隔符
    String[] split = filename.split("\\.");
    //注意判断截取后的数组长度，数组最后一个元素是后缀名
    if (split.length > 1) {
      return split[split.length - 1];
    } else {
      return "";
    }
  }

  /**
   * @return org.springframework.http.ResponseEntity<org.springframework.core.io.FileSystemResource>
   * @Author 欧永卿
   * @Description //TODO 文件发起下载
   * @Date 10:08 2021-07-05
   * @Param [file]
   **/
  public ResponseEntity<FileSystemResource> export(File file) {
    if (file == null) {
      return null;
    }
    HttpHeaders headers = new HttpHeaders();
    headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
    try {
      headers.add("Content-Disposition", "attachment; filename=" + String.valueOf(
          URLEncoder.encode(file.getAbsolutePath(), "UTF-8")));
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    headers.add("Pragma", "no-cache");
    headers.add("Expires", "0");
    headers.add("Last-Modified", new Date().toString());
    headers.add("ETag", String.valueOf(System.currentTimeMillis()));
    return ResponseEntity
        .ok()
        .headers(headers)
        .contentLength(file.length())
        .contentType(MediaType.parseMediaType("application/octet-stream"))
        .body(new FileSystemResource(file));
  }


  /**
   * @param file
   * @param savePath
   * @return java.util.Map<java.lang.String, java.lang.Object> 文件上传接口的解析，保存。map结构中包含：msg，返回消息.
   * newfile，保存的文件(file).  old 旧的文件名
   * @Author oyq
   * @Date 2022/3/23 11:21
   **/
  public Map<String, Object> upLoadFiles(MultipartFile file, String savePath) {
    Map<String, Object> map = new HashMap<>();
    Map<String, Object> msgMap = new HashMap<>();
    //设置支持最大上传的文件，这里是1024*1024*20=20M
    long MAX_SIZE = 20971520L;
    //获取要上传文件的名称
    String fileName = file.getOriginalFilename();
    //如果名称为空，返回一个文件名为空的错误
    if (StringUtils.isEmpty(fileName)) {
      msgMap.put("code", "0");
      msgMap.put("msg", "文件名为空");
      return map;
    }
    //如果文件超过最大值，返回超出可上传最大值的错误
    if (file.getSize() > MAX_SIZE) {
      msgMap.put("code", "0");
      msgMap.put("msg", "文件过大");
      return map;
    }
    //获取到后缀名
    String suffixName =
        fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".")) : null;
    //文件的保存重新按照雪花算法命名
    String newName = snowflakeMakeConf.snowflakeStringId() + suffixName;
    File newFile = new File(savePath, newName);
    if (!newFile.getParentFile().exists()) {
      newFile.getParentFile().mkdirs();
    }
    try {
      //文件写入
      file.transferTo(newFile);
    } catch (IOException e) {
      e.printStackTrace();
    }
    msgMap.put("code", "200");
    msgMap.put("msg", "数据上传成功");
    map.put("newfile", newFile);
    map.put("oldfileName", fileName);
    log.info(fileName + ",文件上传到" + newFile.getPath());
    return map;
  }

}
