package cn.edu.whu.boot.photozip.util;

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

public class ZipUtil {

    /**
     * 直接压缩指定的文件夹，并保持文件夹结构
     * @param folderPath  需要压缩的文件夹路径
     * @param zipPath  生成的 ZIP 文件路径
     */
    public static void createZip(String folderPath, String zipPath) {
        File folder = new File(folderPath);
        if (!folder.exists() || !folder.isDirectory()) {
            throw new IllegalArgumentException("路径不是有效的文件夹: " + folderPath);
        }

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
            addDirectoryToZip(folder, folder.getParentFile(), zos);
        } catch (IOException e) {
            throw new RuntimeException("创建 ZIP 失败", e);
        }
    }

    /**
     * 递归添加文件夹及其内容到 ZIP 文件中
     * @param folder  需要压缩的文件夹
     * @param baseFolder  ZIP 内的相对路径起始点
     * @param zos  Zip 输出流
     */
    private static void addDirectoryToZip(File folder, File baseFolder, ZipOutputStream zos) throws IOException {
        File[] files = folder.listFiles();
        if (files == null) return;

        for (File file : files) {
            String zipEntryName = baseFolder.toURI().relativize(file.toURI()).getPath();
            if (file.isDirectory()) {
                // 目录项需要以 `/` 结尾，以表明是目录
                zos.putNextEntry(new ZipEntry(zipEntryName.endsWith("/") ? zipEntryName : zipEntryName + "/"));
                zos.closeEntry();
                addDirectoryToZip(file, baseFolder, zos);
            } else {
                addFileToZip(file, zipEntryName, zos);
            }
        }
    }

    /**
     * 将文件添加到 ZIP 文件中，并保持相对路径
     * @param file  需要添加的文件
     * @param zipEntryName  ZIP 入口名称（相对路径）
     * @param zos  Zip 输出流
     */
    private static void addFileToZip(File file, String zipEntryName, ZipOutputStream zos) throws IOException {
        // 创建输入流读取文件
        try (FileInputStream fis = new FileInputStream(file)) {
            // 为文件创建 ZipEntry
            zos.putNextEntry(new ZipEntry(zipEntryName));

            // 创建缓冲区并读取文件内容
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }

            // 关闭文件的 ZipEntry
            zos.closeEntry();
        }
    }

}
