package com.cpp.web.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
public class ZipUtil {

    private static final int BUFFER_SIZE = 2 * 1024;


    /**
     * 压缩目录到ZIP文件
     *
     * @param sourceDirPath 源目录路径
     * @param zipFilePath   目标ZIP文件路径
     * @return 压缩成功返回true，否则返回false
     */
    public static boolean zip(String sourceDirPath, String zipFilePath) {
        File sourceDir = new File(sourceDirPath);
        if (!sourceDir.isDirectory()) {
            log.error("源路径不是一个有效的目录：" + sourceDirPath);
            return false;
        }

        try (FileOutputStream fos = new FileOutputStream(zipFilePath);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            if (toZip(sourceDirPath, zos, true)) {
                // 注意：删除目录的操作应该非常谨慎，这里只是示例
                // 在实际应用中，应该由调用者决定是否删除源目录
                delFile(sourceDir);
                // log.info("压缩成功，已删除【" + sourceDirPath + "】目录");
                log.info("压缩成功");
                return true;
            } else {
                log.error("压缩失败：无法压缩【" + sourceDirPath + "】目录");
                return false;
            }
        } catch (IOException e) {
            log.error("压缩过程中发生错误：", e);
            return false;
        }
    }

    /**
     * 目录转为zip包（静态方法）
     *
     * @param srcDir           源目录路径
     * @param zos              ZIP输出流
     * @param keepDirStructure 是否保留原来的目录结构
     * @return 压缩成功返回true，否则返回false
     * @throws RuntimeException 如果发生无法处理的异常，则抛出运行时异常
     */
    private static boolean toZip(String srcDir, ZipOutputStream zos, boolean keepDirStructure) {
        File sourceFile = new File(srcDir);
        try {
            compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
            return true;
        } catch (IOException e) {
            log.error("已上报文件压缩错误！！！", e);
            return false;
        }
    }

    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件或目录
     * @param zos              ZIP输出流
     * @param entryName        ZIP条目名称
     * @param keepDirStructure 是否保留原来的目录结构
     * @throws IOException 如果发生I/O错误，则抛出IOException
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String entryName, boolean keepDirStructure) throws IOException {
        if (sourceFile.isFile()) {
            zos.putNextEntry(new ZipEntry(entryName));
            try (FileInputStream fis = new FileInputStream(sourceFile)) {
                byte[] buffer = new byte[BUFFER_SIZE];
                int len;
                while ((len = fis.read(buffer)) != -1) {
                    zos.write(buffer, 0, len);
                }
            }
            zos.closeEntry();
        } else if (sourceFile.isDirectory()) {
            File[] files = sourceFile.listFiles();
            if (files != null) {
                for (File file : files) {
                    String newName = keepDirStructure ? entryName + "/" + file.getName() : file.getName();
                    compress(file, zos, newName, keepDirStructure);
                }
                if (keepDirStructure && files.length == 0) {
                    zos.putNextEntry(new ZipEntry(entryName + "/"));
                    zos.closeEntry();
                }
            }
        }
    }

    // 注意：delFile 方法已经被注释掉，因为它在实际应用中可能是一个危险的操作
    // 如果您确实需要它，请确保在安全的上下文中使用，并且用户已经明确同意删除操作
    public static boolean delFile(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                delFile(f);
            }
        }
        return file.delete();
    }

}
