package shop.alien.util.file;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 文件工具类
 *
 * @author ssk
 * @version 1.0
 * @date 2020/5/9 14:34
 */
@Slf4j
public class FileUtil {

    public static void main(String[] args) {
        String folderName = "1";
        String path = "Y:\\HHH\\123分类\\" + folderName;
        String videoPath = "Y:\\HHH\\123分类\\" + folderName + "\\-视频";
//        updateFileNameByLastModified(path);
//        updateFileNameByLastModified(videoPath);
        updateFileNameByLastModified("Z:\\douyin\\视频");
        updateFileNameByLastModified("Z:\\douyin\\图片");
    }

    /**
     * 复制文件
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @param fileName   文件名
     */
    public static boolean copyFile(String sourcePath, String targetPath, String fileName) {
        try {
            //创建输入流对象
            FileInputStream fis = new FileInputStream(sourcePath + File.separator + fileName);
            //创建输出流对象
            FileOutputStream fos = new FileOutputStream(targetPath + File.separator + fileName);
            //创建搬运工具
            byte[] bytes = new byte[1024 * 8];
            //创建长度
            int len;
            //循环读取数据
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
            //释放资源
            fos.close();
            fis.close();
            return true;
        } catch (Exception e) {
            log.error("FileUtil/copyFile ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 移动文件
     *
     * @param sourcePath 源文件全路径
     * @param targetPath 目标文件全路径
     * @return boolean
     */
    public static Boolean moveFile(String sourcePath, String targetPath) {
        sourcePath = sourcePath.replace("\\", "/");
        targetPath = targetPath.replace("\\", "/");
        String fileName = sourcePath.substring(sourcePath.lastIndexOf("/") + 1);
        return moveFile(sourcePath.substring(0, sourcePath.lastIndexOf("/")), targetPath, fileName);
    }

    /**
     * 移动文件
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @param fileName   文件名
     * @return boolean
     */
    public static Boolean moveFile(String sourcePath, String targetPath, String fileName) {
        try {
            boolean flag = false;
            String newFileName = "";
            //创建输入流对象
            FileInputStream fis = new FileInputStream(sourcePath + "/" + fileName);
            File targetFile = new File(targetPath + "/" + fileName);
            if (targetFile.exists()) {
                String fileType = fileName.substring(fileName.lastIndexOf("."));
                String fileRealName = fileName.substring(0, fileName.lastIndexOf("."));
                int randomMun = (int) (Math.random() * 10000);
                newFileName = fileRealName + "_" + randomMun + fileType;
            }
            //创建输出流对象
            FileOutputStream fos = new FileOutputStream(targetPath + "/" + newFileName);
            //创建搬运工具
            byte[] bytes = new byte[1024 * 8];
            //创建长度
            int len;
            //循环读取数据
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
            //释放资源
            fos.close();
            fis.close();
            //删除源文件
            if (new File(sourcePath + "/" + fileName).delete()) {
                flag = true;
            }
            return flag;
        } catch (Exception e) {
            log.error("FileUtil/moveFile ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 使用Apache Commons IO库移动文件
     *
     * @param sourcePath 源路径
     * @param targetPath 目标路径
     * @param fileName   文件名
     * @return boolean
     */
    public static boolean apacheMoveFile(String sourcePath, String targetPath, String fileName) {
        try {
            if (null == sourcePath || sourcePath.isEmpty()) {
                throw new Exception("移动文件错误, 原路径为空");
            }
            if (null == targetPath || targetPath.isEmpty()) {
                throw new Exception("移动文件错误, 目标路径为空");
            }
            if (!new File(targetPath).exists()) {
                new File(targetPath).mkdirs();
            }
            File sourceFile = new File(sourcePath + "/" + fileName);
            File destFile = new File(targetPath + "/" + fileName);
            if (destFile.exists()) {
                String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
                String fileRealName = fileName.substring(0, fileName.lastIndexOf("."));
                int randomMun = (int) (Math.random() * 10000);
                fileName = fileRealName + "_" + randomMun + fileType;
                destFile = new File(targetPath + "/" + fileName);
            }
            FileUtils.moveFile(sourceFile, destFile);
            return true;
        } catch (Exception e) {
            log.error("FileUtil/apacheMoveFile ERROR Msg={}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除文件
     *
     * @param filePath 文件路径
     */
    public static boolean deleteFile(String filePath) {
        log.info("FileUtil/deleteFile path: {}", filePath);
        try {
            File file = new File(filePath);
            if (file.exists()) {
                return file.delete();
            }
            return false;
        } catch (Exception e) {
            log.error("FileUtil/deleteFile ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 判断文件夹名称是否合法
     *
     * @param folderName 文件夹名称
     * @return result
     */
    public static boolean folderNameTest(String folderName) {
        boolean result = true;
        String[] letters = new String[]{"/", "\\", ":", "*", "?", "\"", "<", ">", "|"};
        for (String letter : letters) {
            if (folderName.contains(letter)) {
                result = false;
                break;
            }
        }
        return result;
    }

    /**
     * 替换文件夹非法字符
     *
     * @param folderName 文件夹名称
     * @return result
     */
    public static String folderSymbol(String folderName) {
        String symbol = "";
        String[] letters = new String[]{"/", "\\", ":", "*", "?", "\"", "<", ">", "|"};
        for (String letter : letters) {
            if (folderName.contains(letter)) {
                symbol = letter;
                break;
            }
        }
        return symbol;
    }

    /**
     * 根据文件修改时间修改文件名
     *
     * @param path 处理路径
     * @return boolean
     */
    public static boolean updateFileNameByLastModified(String path) {
        boolean flag = false;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
            File file = new File(path);
            List<String> fileNameList = new ArrayList<>();
            if (file.isDirectory()) {
                //获取当前文件夹中所有文件名
                File[] files = file.listFiles();
                //判断文件夹不为空
                if (null != files && files.length > 0) {
                    //给定路径目录进行排序
                    SortFileName(files);
                    //存储文件名
                    for (File oneFile : files) {
                        fileNameList.add(oneFile.getName());
                    }
                    //获取文件名并修改
                    for (int i = 0; i < files.length; i++) {
                        String fileName = files[i].getName();
                        if (files[i].isDirectory()) {
                            System.err.println("===================================");
                            System.err.println(fileName + ": 为文件夹, 跳过并继续");
                            System.err.println("===================================");
                            continue;
                        }
                        long lastModified = files[i].lastModified();
                        Date date = new Date(lastModified);
                        String format = sdf.format(date);
                        System.out.println("原文件名: " + fileName);
                        String fileType = fileName.substring(fileName.lastIndexOf("."));
                        //判断文件名是否存在
                        String lastFileName = renameFile(fileNameList, format, fileType);
                        System.out.println("新文件名: " + lastFileName);
                        //修改暂存文件名
                        fileNameList.set(i, lastFileName);
                        boolean result = new File(path + File.separator + fileName).renameTo(new File(path + File.separator + lastFileName));
                        if (!result) {
                            log.error("FileUtil/updateFileNameByLastModified 修改文件名错误,原文件名: " + fileName);
                            break;
                        } else {
                            log.info("FileUtil/updateFileNameByLastModified: " + fileName + "\t>>>\t" + lastFileName);
                        }
                        System.out.println("===================================");
                    }
                    flag = true;
                }
            }
            return flag;
        } catch (Exception e) {
            log.error("FileUtil/updateFileNameByLastModified ERROR Msg={}", e.getMessage());
            return flag;
        }
    }

    /**
     * 递归处理文件名
     *
     * @param fileNameList 文件名list
     * @param fileName     文件名
     * @param fileType     文件类型
     * @return 文件名
     */
    private static String renameFile(List<String> fileNameList, String fileName, String fileType) {
        String lastFileName = fileName + fileType;
        if (fileName.length() == 15) {
            fileName += "_0000";
            //文件名不存在, 拼接后返回
            lastFileName = fileName + fileType;
            renameFile(fileNameList, fileName, fileType);
        }
        //判断文件名是否存在,包括0000
        if (fileNameList.contains(lastFileName) || fileNameList.contains(fileName + "_0000" + fileType)) {
            //相同时间存在多个,第二个加千位数后缀
            if (fileName.length() <= 15) {
                fileName += "_0001";
                //递归查询是否存在
                lastFileName = renameFile(fileNameList, fileName, fileType);
            } else {
                //三次+后, 获取后缀+1,并格式化为千位
                String fileStart = fileName.substring(0, 15);
                String num_str = fileName.substring(16);
                int num = Integer.parseInt(num_str);
                num += 1;
                if (num < 10) {
                    fileName = fileStart + "_" + "000" + num;
                } else if (num < 100) {
                    fileName = fileStart + "_" + "00" + num;
                } else if (num < 1000) {
                    fileName = fileStart + "_" + "0" + num;
                } else {
                    fileName = fileStart + "_" + num;
                }
                //递归查询是否存在
                lastFileName = renameFile(fileNameList, fileName, fileType);
            }
        }
        return lastFileName;
    }

    /**
     * 对某文件夹下的文件名像win里一样排序
     *
     * @param fileNames 文件名
     */
    private static void SortFileName(String[] fileNames) {
        Arrays.sort(fileNames, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                if (returnDouble(s1) < returnDouble(s2)) return -1;
                else if (returnDouble(s1) > returnDouble(s2)) return 1;
                else return 0;
            }

            public double returnDouble(String str) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < str.length(); i++) {
                    if (Character.isDigit(str.charAt(i))) sb.append(str.charAt(i));
                    else if (str.charAt(i) == '.' && i < str.length() - 1 && Character.isDigit(str.charAt(i + 1)))
                        sb.append(str.charAt(i));
                    else break;
                }
                if (sb.toString().isEmpty()) return 0;
                else return Double.parseDouble(sb.toString());
            }

        });
    }

    /**
     * 对某文件夹下的文件名像win里一样排序
     *
     * @param fileNames 文件
     */
    public static void SortFileName(File[] fileNames) {
        Arrays.sort(fileNames, new Comparator<File>() {
            @Override
            public int compare(File s1, File s2) {
                if (returnDouble(s1) < returnDouble(s2)) return -1;
                else if (returnDouble(s1) > returnDouble(s2)) return 1;
                else return 0;
            }

            public double returnDouble(File file) {
                StringBuilder sb = new StringBuilder();
                String str = file.getName();
                for (int i = 0; i < str.length(); i++) {
                    if (Character.isDigit(str.charAt(i))) sb.append(str.charAt(i));
                    else if (str.charAt(i) == '.' && i < str.length() - 1 && Character.isDigit(str.charAt(i + 1)))
                        sb.append(str.charAt(i));
                    else break;
                }
                if (sb.toString().isEmpty()) return 0;
                else return Double.parseDouble(sb.toString());
            }

        });
    }

    /**
     * 递归获取某路径下的所有文件，文件夹，并输出
     */
    public static void getFiles(String path) {
        File file = new File(path);
        // 如果这个路径是文件夹
        if (file.isDirectory()) {
            // 获取路径下的所有文件
            File[] files = file.listFiles();
            assert files != null;
            for (File value : files) {
                // 如果还是文件夹 递归获取里面的文件 文件夹
                if (value.isDirectory()) {
                    System.out.println("目录：" + value.getPath());
                    getFiles(value.getPath());
                } else {
                    System.out.println("文件：" + value.getPath());
                }
            }
        } else {
            System.out.println("文件：" + file.getPath());
        }
    }

    /**
     * 判断文件夹是否存在
     *
     * @param path 文件夹路径
     * @return 是否存在
     */
    public static boolean folderExist(String path) {
        return new File(path).exists();
    }

    /**
     * 创建文件夹
     *
     * @param path 文件夹路径
     * @return 是否成功
     */
    public static boolean mkdir(String path) {
        return new File(path).mkdir();
    }

    /**
     * 获取文件大小
     *
     * @param filePath 文件路径
     * @return 字节
     */
    public static Long getFileSize(String filePath) {
        Path path = Paths.get(filePath);
        try {
            return Files.size(path);
        } catch (IOException e) {
            log.error("FileUtil.getFileSize 获取文件大小失败: {}", e.getMessage());
            return 0L;
        }
    }

    /**
     * 获取文件大小
     *
     * @param file 文件
     * @return 字节
     */
    public static Long getFileSize(File file) {
        return file.length();
    }

    /**
     * 反斜杠转换为正斜杠
     *
     * @param filePath 路径
     * @return 替换后路径
     */
    public static String filePathConvert(String filePath) {
        return filePath.replace("\\", "/");
    }


    /**
     * 文件转换
     *
     * @param multipartFile 前端上传的文件
     * @return File
     */
    public static File convert(MultipartFile multipartFile) {
        try {
            // 创建一个临时文件
            File tempFile = File.createTempFile("upload-", ".tmp");
            // 将MultipartFile内容转存到临时文件中
            multipartFile.transferTo(tempFile);
            return tempFile;
        } catch (IOException e) {
            log.error("FileUtil.convert ERROR: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取文件名称和类型
     *
     * @param multipartFile
     * @return
     */
    public static Map<String, String> getFileNameAndType(MultipartFile multipartFile) {
        String originalFilename = multipartFile.getOriginalFilename();
        Map<String, String> map = new HashMap<>();
        if (originalFilename == null || originalFilename.isEmpty()) {
            map.put("name", "");
            map.put("type", "");
            return map;
        }
        int lastDotIndex = originalFilename.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == originalFilename.length() - 1) {
            // 没有扩展名或点号在最后
            map.put("name", originalFilename);
            map.put("type", "");
        } else {
            String fileName = originalFilename.substring(0, lastDotIndex);
            String fileType = originalFilename.substring(lastDotIndex + 1);
            map.put("name", fileName);
            map.put("type", fileType);
        }
        return map;
    }

    /**
     * 获取文件名称和类型
     *
     * @param file
     * @return
     */
    public static Map<String, String> getFileNameAndType(File file) {
        String originalFilename = file.getName();
        Map<String, String> map = new HashMap<>();
        if (originalFilename == null || originalFilename.isEmpty()) {
            map.put("name", "");
            map.put("type", "");
            return map;
        }
        int lastDotIndex = originalFilename.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == originalFilename.length() - 1) {
            // 没有扩展名或点号在最后
            map.put("name", originalFilename);
            map.put("type", "");
        } else {
            String fileName = originalFilename.substring(0, lastDotIndex);
            String fileType = originalFilename.substring(lastDotIndex + 1);
            map.put("name", fileName);
            map.put("type", fileType);
        }
        return map;
    }
}
