package com.malk.utils;

import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.springframework.core.io.ClassPathResource;

import javax.annotation.Nullable;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public abstract class UtilFile {

    ////////////////////////////// File Path //////////////////////////////

    /**
     * 匹配路径: 自动追加年月日作为目录
     * -
     * 文件上传存储,必须是绝对路径. 日志的配置地址可以是相对路径
     */
    public static File mkdirIfNot(@Nullable String fileName, @Nullable String dirName) {
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String outputFile = dirName + "/" + date + "/" + fileName;
        File file = new File(outputFile);
        // 创建 mkdirIfNot
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        return file;
    }

    /**
     * 根据路径删除指定的目录或文件，无论存在与否
     */
    public static boolean DeleteFolder(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {  // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }

    /**
     * 删除单个文件
     */
    public static boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     */
    public static boolean deleteDirectory(String sPath) {
        // 如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        // 如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        // 删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            // 删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) break;
            } // 删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        // 删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    ////////////////////////////// File & 字节/流 //////////////////////////////

    /**
     * 文件转化为byte字节数组
     */
    public static byte[] fileToByteArray(File file) {
        byte[] data = null;
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            data = baos.toByteArray();
            fis.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 文件全路径转Base64
     */
    public static String fileToBase64(String path) {
        String base64 = null;
        InputStream in = null;
        try {
            File file = new File(path);
            in = new FileInputStream(file);
            byte[] bytes = new byte[(int) file.length()];
            in.read(bytes);
            base64 = new String(Base64.encodeBase64(bytes), "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return base64;
    }

    /**
     * Base64转文件储存
     */
    public static void base64ToFile(String outFilePath, String base64, String outFileName) {
        File file = null;
        //创建文件目录
        String filePath = outFilePath;
        File dir = new File(filePath);
        if (!dir.exists() && !dir.isDirectory()) {
            dir.mkdirs();
        }
        BufferedOutputStream bos = null;
        java.io.FileOutputStream fos = null;
        try {
            byte[] bytes = Base64.decodeBase64(base64);
            file = new File(filePath + "/" + outFileName);
            fos = new java.io.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();
                }
            }
        }
    }

    ////////////////////////////// Resource 读取 //////////////////////////////

    /**
     * 项目包文件, 读取 [ ppExt: 读取 Resource 必须 ]
     * -
     * 1. ClassPathResource, 需要打包/编译后才能访问到. 识别不是架包内内容
     * 2. 路径若 WebConfiguration 配置, 可使用配置别名. [详见 WebConfiguration]
     */
    @SneakyThrows
    public static InputStream readPackageResource(String path) {
        ClassPathResource classPathResource = new ClassPathResource(path);
        InputStream inputStream = classPathResource.getInputStream();
        return inputStream;
    }

    /**
     * 项目包JSON, 读取 [ ppExt: 读取 Resource 必须 ]
     */
    public static Object readJsonObjectFromResource(String path) {
        return _readJsonObjectFromStream(readPackageResource(path));
    }

    /// ppExt: 文件流, 转JSONObject
    /// 1. 使用 JSONUtil.class.getClassLoader().getResource(path).getPath(); 本地访问路径正常, 部署服务器路径访问访问, 需要读取 Resource
    /// 2. 若是读取本地json, 文件不能使用 .josn 后缀, 会被转义导致解析异常 / 但若是 Resource 资源则不受影响, [访问路径详见 WebConfiguration]
    @SneakyThrows
    private static Object _readJsonObjectFromStream(InputStream inputStream) {
        Reader reader = new InputStreamReader(inputStream, "utf-8");
        int ch = 0;
        StringBuffer sb = new StringBuffer();
        while ((ch = reader.read()) != -1) {
            sb.append((char) ch);
        }
        reader.close();
        return JSON.parse(sb.toString());
    }

    /**
     * 文件绝对路径转json
     */
    @SneakyThrows
    public static Object readJsonObjectFromFile(String absolutePath) {
        File jsonFile = new File(absolutePath);
        FileReader fileReader = new FileReader(jsonFile);
        // 通过文件, 读取流转json对象
        Object jsonObject = _readJsonObjectFromStream(new FileInputStream(jsonFile));
        fileReader.close();
        return jsonObject;
    }
}
