package shop.alien.util.compress;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;

/**
 * 解压文件工具类
 *
 * @author ssk
 * @version 1.0
 * @date 2024/6/5 9:25
 */
@Slf4j
public class DecompressionUtil {

    public static void main(String[] args) {
        String sourcePath = "Z:/douyin";
        String targetPath = "E:/Cache";
        String fileName = "ootd穿搭晚安20240604002708399950211.zip";
        unZip(sourcePath, targetPath, fileName);
    }

    /**
     * 解压zip
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @return boolean
     */
    public static boolean unZip(String sourcePath, String targetPath, String fileName) {
        log.info("DecompressionUtil.unZip 文件名: {}, 文件路径: {}, 解压路径: {}", fileName, sourcePath, targetPath);
        boolean flag = false;
        targetPath += "/" + fileName.substring(0, fileName.lastIndexOf("."));
        File srcFile = new File(sourcePath + "/" + fileName);
        if (!srcFile.exists()) {
            log.info("DecompressionUtil.unZip ERROR: 所指文件不存在");
        }
        // 开始解压
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcFile);
            Enumeration<?> entries = zipFile.getEntries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                System.out.println("解压: " + entry.getName());
                // 如果是文件夹，就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = targetPath + "/" + entry.getName();
                    File dir = new File(dirPath);
                    dir.mkdirs();
                } else {
                    // 如果是文件，就先创建一个文件，然后用io流把内容copy过去
                    File targetFile = new File(targetPath + "/" + entry.getName());
                    // 保证这个文件的父文件夹必须要存在
                    if (!targetFile.getParentFile().exists()) {
                        targetFile.getParentFile().mkdirs();
                    }
                    targetFile.createNewFile();
                    // 将压缩文件内容写入到这个文件中
                    InputStream is = zipFile.getInputStream(entry);
                    FileOutputStream fos = new FileOutputStream(targetFile);
                    int len;
                    byte[] buf = new byte[2048];
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    // 关流顺序，先打开的后关闭
                    fos.close();
                    is.close();
                }
            }
            flag = true;
        } catch (Exception e) {
            log.info("DecompressionUtil.unZip ERROR: {}", e.getMessage());
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException e) {
                    log.info("DecompressionUtil.unZip ERROR: {}", e.getMessage());
                }
            }
        }
        return flag;
    }

    /**
     * 解压7z
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @return boolean
     */
    public static boolean un7z(String sourcePath, String targetPath, String fileName) {
        log.info("DecompressionUtil.un7z 文件名: {}, 文件路径: {}, 解压路径: {}", fileName, sourcePath, targetPath);
        targetPath += "/" + fileName.substring(0, fileName.lastIndexOf("."));
        boolean flag = false;
        SevenZFile zIn = null;
        try {
            File file = new File(sourcePath + "/" + fileName);
            zIn = new SevenZFile(file);
            SevenZArchiveEntry entry;
            while ((entry = zIn.getNextEntry()) != null) {
                if (!entry.isDirectory()) {
                    File newFile = new File(targetPath, entry.getName());
                    if (!newFile.exists()) {
                        new File(newFile.getParent()).mkdirs();
                    }
                    OutputStream out = Files.newOutputStream(newFile.toPath());
                    BufferedOutputStream bos = new BufferedOutputStream(out);
                    int len = -1;
                    byte[] buf = new byte[(int) entry.getSize()];
                    while ((len = zIn.read(buf)) != -1) {
                        bos.write(buf, 0, len);
                    }
                    bos.flush();
                    bos.close();
                    out.close();
                }
            }
            flag = true;
        } catch (Exception e) {
            log.info("DecompressionUtil.un7z ERROR: {}", e.getMessage());
        } finally {
            try {
                if (zIn != null) zIn.close();
            } catch (IOException e) {
                log.info("DecompressionUtil.un7z ERROR: {}", e.getMessage());
            }
        }
        return flag;
    }

    /**
     * 解压tar
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @return boolean
     */
    public static boolean unTar(String sourcePath, String targetPath, String fileName) {
        log.info("DecompressionUtil.unTar 文件名: {}, 文件路径: {}, 解压路径: {}", fileName, sourcePath, targetPath);
        targetPath += "/" + fileName.substring(0, fileName.lastIndexOf("."));
        boolean flag = false;
        try (FileInputStream fis = new FileInputStream(sourcePath + "/" + fileName);
             BufferedInputStream bis = new BufferedInputStream(fis);
             TarArchiveInputStream tarInputStream = new TarArchiveInputStream(bis)) {
            TarArchiveEntry tarEntry;
            while ((tarEntry = tarInputStream.getNextTarEntry()) != null) {
                File outputFile = new File(targetPath, tarEntry.getName());
                if (tarEntry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    outputFile.getParentFile().mkdirs();
                    try (OutputStream outputStream = Files.newOutputStream(outputFile.toPath())) {
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = tarInputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, bytesRead);
                        }
                    }
                }
            }
            flag = true;
        } catch (IOException e) {
            log.info("DecompressionUtil.unTar ERROR: {}", e.getMessage());
        }
        return flag;
    }


    /**
     * 解压tar.gz
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @return boolean
     */
    public static boolean unTarGz(String sourcePath, String targetPath, String fileName) {
        log.info("DecompressionUtil.unTarGz 文件名: {}, 文件路径: {}, 解压路径: {}", fileName, sourcePath, targetPath);
        targetPath += "/" + fileName.substring(0, fileName.lastIndexOf("."));
        Path source = Paths.get(sourcePath + "/" + fileName);
        Path target = Paths.get(targetPath);
        boolean flag = false;
        try (InputStream fi = Files.newInputStream(source);
             BufferedInputStream bi = new BufferedInputStream(fi);
             GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
             TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {
            ArchiveEntry entry;
            while ((entry = ti.getNextEntry()) != null) {
                String entryName = entry.getName();
                Path targetDirResolved = target.resolve(entryName);
                Path newDestPath = targetDirResolved.normalize();
                if (entry.isDirectory()) {
                    newDestPath = Paths.get(targetPath + "/" + entryName);
                    Files.createDirectories(newDestPath);
                } else {
                    Files.copy(ti, newDestPath, StandardCopyOption.REPLACE_EXISTING);
                }
            }
            flag = true;
        } catch (Exception e) {
            log.info("DecompressionUtil.unTarGz ERROR: {}", e.getMessage());
        }
        return flag;
    }

    /**
     * 解压gzip
     *
     * @param sourcePath 原文件路径
     * @param targetPath 目标文件路径
     * @return boolean
     */
    public static boolean unGzip(String sourcePath, String targetPath, String fileName) {
        log.info("DecompressionUtil.unGzip 文件名: {}, 文件路径: {}, 解压路径: {}", fileName, sourcePath, targetPath);
        targetPath += "/" + fileName.substring(0, fileName.lastIndexOf("."));
        boolean flag = false;
        try {
            FileInputStream fin = new FileInputStream(sourcePath + "/" + fileName);
            //建立gzip解压工作流
            GZIPInputStream gzipInputStream = new GZIPInputStream(fin);
            //建立解压文件输出流
            FileOutputStream fileOutputStream = new FileOutputStream(targetPath);
            int num;
            byte[] buf = new byte[1024];

            while ((num = gzipInputStream.read(buf, 0, buf.length)) != -1) {
                fileOutputStream.write(buf, 0, num);
            }
            gzipInputStream.close();
            fileOutputStream.close();
            fin.close();
            flag = true;
        } catch (IOException e) {
            log.info("DecompressionUtil.unGzip ERROR: {}", e.getMessage());
        }
        return flag;
    }

}
