package com.bcxin.ferry.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * description：文件拆分合并
 * author：linchunpeng
 * date：2024/3/15
 */
@Slf4j
public class FileSpiltMergeUtil {

    /**
     * description：拆分子文件，返回子文件列表
     * author：linchunpeng
     * date：2024/3/12
     */
    public static List<String> splitFile(long maxSize, File original) {
        log.info("文件：{}，开始拆分", original.getAbsolutePath());
        String name = original.getName();
        if (name.contains(".")) {
            name = name.substring(0, name.lastIndexOf("."));
        }
        name += "-s-";
        //拆分大小，比最大小1M，防止出问题
        long size = (long) (maxSize * 0.8);
        //子文件存放目录，与原始文件同目录
        File directory = original.getParentFile();
        //拆分出来的子文件id
        List<String> childrenFilePathList = new ArrayList<>();
        int count = 1;
        try (FileInputStream fis = new FileInputStream(original)) {
            // 单文件大小一个数组能读取到范围
            if (size <= Integer.MAX_VALUE - 8) {
                //最大数组大小定义为Integer.MAX_VALUE - 8，作为自己需要8 bytes存储大小（Integer.MAX_VALUE == 2G）
                byte[] bytes = new byte[(int) size];
                int readSize;   // readSize 读取的字节数
                while (fis.available() != 0) {//可读取字节数
                    readSize = fis.read(bytes);
                    File outFile = new File(directory, name + count++ + ".kfm");
                    // 用输出流创建子文件
                    FileOutputStream fos = new FileOutputStream(outFile);
                    fos.write(bytes, 0, readSize);//这么做防止写入重复的字节
                    log.info("拆分出文件：{}", outFile.getName());
                    fos.close();
                    childrenFilePathList.add(outFile.getAbsolutePath());
                }
            } else {
                // 一次读取不能完整读取一个文件  size > Integer.MAX_VALUE
                // 当前被分隔的文件是否以分隔完毕
                while (fis.available() != 0) { // 每循环一个会创建一个子文件
                    // 用输出流创建子文件
                    File outFile = new File(directory, name + count++ + ".part");
                    FileOutputStream fos = new FileOutputStream(outFile);
                    long sum = size; // 单文件大小
                    while (sum > Integer.MAX_VALUE - 8 && fis.available() != 0) {
                        byte[] bytes = new byte[Integer.MAX_VALUE - 8];
                        int readSize = fis.read(bytes);
                        fos.write(bytes, 0, readSize);
                        sum -= readSize;
                    }
                    // 没有满足单文件大小, 还有内容没读取
                    if (fis.available() != 0) {
                        byte[] bytes = new byte[(int) sum];
                        int readSize = fis.read(bytes);
                        fos.write(bytes, 0, readSize);
                    }
                    log.info("拆分出文件：{}", outFile.getName());
                    fos.close();
                    childrenFilePathList.add(outFile.getAbsolutePath());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return childrenFilePathList;
    }



    /**
     * 将指定目录中的多个文件片段依次序合并到同一个文件中，并返回合并后的文件体积
     * 合并后文件被损坏，原因：合并时子文件的顺序不对
     * 解决方案：
     * 1. 拆分时文件名按照顺序命名（单线程下可用时间戳做文件名）
     * 2. 根据文件名自定义排序规则
     */
    public static long join(File[] files , File target) {
        long size = 0; // 声明用于统计合并后的文件体积的变量
        // 参数校验
        if (files == null || files.length == 0) {
            return size;
        }
        // 参数校验
        if (target == null) {
            return size;
        }
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdirs();
        }
        // 合并文件
        // 保证顺序
        Arrays.sort(files, (f1, f2) -> {
            String name1 = f1.getName();
            String name2 = f2.getName();
            int index1 = Integer.parseInt(name1.substring(name1.indexOf("-s-")+3, name1.length()-4));
            int index2 = Integer.parseInt(name2.substring(name2.indexOf("-s-")+3, name2.length()-4));
            return index1 - index2;
        });
        try {
            FileOutputStream fos = new FileOutputStream(target); // 创建文件输出流
            for (File file : files) { // 遍历文件片段
                FileInputStream fileInputStream = new FileInputStream(file);
                while (fileInputStream.available() != 0) {
                    byte[] bytes = new byte[1024];
                    int readSize = fileInputStream.read(bytes);
                    fos.write(bytes, 0, readSize);
                }
                fileInputStream.close();
                size += file.length();
            }
            fos.close();
        } catch (IOException e) {
            log.error("合并文件异常：{}", e.getMessage(), e);
        }
        return size;
    }


    public static void main(String[] args) {
//        File file = new File("/Users/linchunpeng/Downloads/20240311041100445/30741696906156_.pic_hd.jpg");
//        splitFile(1*1024*1024, file);
//        File dir = new File("/Users/linchunpeng/Downloads/20240311041100445");
//        File[] files = dir.listFiles((file, name) -> name.endsWith(".kfm"));
//        File target = new File("/Users/linchunpeng/Downloads/20240311041100445/3.jpg");
//        join(files, target);
    }
}
