package com.qmth.paper.library.common.util;

import cn.hutool.core.collection.CollectionUtil;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.contant.SystemConstant;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @Description: zip4j工具
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2022/8/12
 */
public class Zip4jUtil {
    private final static Logger log = LoggerFactory.getLogger(HttpKit.class);

    /**
     * 压缩zip
     *
     * @param scrPath
     * @param files
     */
    public static void zipFile(String scrPath, List<File> files) {
        Optional.ofNullable(scrPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("原始路径不能为空"));
        if (!scrPath.endsWith(".zip")) {
            throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
        }
        if (CollectionUtils.isEmpty(files)) {
            throw ExceptionResultEnum.ERROR.exception("没有待压缩的文件");
        }
        commonZipFile(scrPath, null, files, null);
    }

    /**
     * 压缩zip
     *
     * @param scrPath
     * @param destPath
     */
    public static void zipFile(String scrPath, String destPath) {
        Optional.ofNullable(scrPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("原始路径不能为空"));
        if (!scrPath.endsWith(".zip")) {
            throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
        }
        Optional.ofNullable(destPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("压缩路径不能为空"));
        commonZipFile(scrPath, destPath, null, null);
    }

    /**
     * 压缩zip带密码
     *
     * @param scrPath
     * @param files
     * @param password
     * @throws ZipException
     */
    public static void zipEncryptFile(String scrPath, List<File> files, String password) {
        Optional.ofNullable(scrPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("原始路径不能为空"));
        if (!scrPath.endsWith(".zip")) {
            throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
        }
        if (CollectionUtils.isEmpty(files)) {
            throw ExceptionResultEnum.ERROR.exception("没有待压缩的文件");
        }
        Optional.ofNullable(password).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("压缩密码不能为空"));
        commonZipFile(scrPath, null, files, password);
    }

    /**
     * 压缩zip带密码
     *
     * @param scrPath
     * @param destPath
     * @param password
     */
    public static void zipEncryptFile(String scrPath, String destPath, String password) {
        Optional.ofNullable(scrPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("原始路径不能为空"));
        if (!scrPath.endsWith(".zip")) {
            throw ExceptionResultEnum.ERROR.exception("压缩文件必须为zip");
        }
        Optional.ofNullable(destPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("压缩路径不能为空"));
        Optional.ofNullable(password).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("压缩密码不能为空"));
        commonZipFile(scrPath, destPath, null, password);
    }

    /**
     * 解压zip
     *
     * @param scrPath
     * @param destPath
     */
    public static void unzip(String scrPath, String destPath) {
        Optional.ofNullable(scrPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("原始路径不能为空"));
        Optional.ofNullable(destPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("解压路径不能为空"));
        commonUnZipFile(scrPath, destPath, null);
    }

    /**
     * 解压zip带密码
     *
     * @param scrPath
     * @param destPath
     * @param password
     */
    public static void unzipEncryptFile(String scrPath, String destPath, String password) {
        Optional.ofNullable(scrPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("原始路径不能为空"));
        Optional.ofNullable(destPath).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("解压路径不能为空"));
        Optional.ofNullable(password).orElseThrow(() -> ExceptionResultEnum.ERROR.exception("解压密码不能为空"));
        commonUnZipFile(scrPath, destPath, password);
    }

    /**
     * 解压zip包
     *
     * @param scrPath
     * @param destPath
     * @param password
     */
    private static void commonUnZipFile(String scrPath, String destPath, String password) {
        try {
            File file = new File(scrPath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
            }
            ZipFile zipFile = new ZipFile(scrPath);
            if (Objects.nonNull(password) && zipFile.isEncrypted()) {
                zipFile.setPassword(password);
            }
            File currentFile = new File(destPath);
            if (!currentFile.exists()) {
                throw ExceptionResultEnum.ERROR.exception("待解压的路径不存在");
            }
            zipFile.extractAll(destPath);
        } catch (ZipException e) {
            log.error(SystemConstant.LOG_ERROR, e);
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }

    /**
     * 压缩zip包
     *
     * @param scrPath
     * @param destPath
     * @param files
     * @param password
     */
    private static void commonZipFile(String scrPath, String destPath, List<File> files, String password) {
        try {
            File file = new File(scrPath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
            }
            // 生成的压缩文件
            ZipFile zipFile = new ZipFile(scrPath);
            ZipParameters parameters = new ZipParameters();
            // 压缩级别
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            // 压缩级别
            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
            if (Objects.nonNull(password)) {
                parameters.setEncryptFiles(true);
                parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
                parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
                parameters.setPassword(password);
            }

            File[] fs = null;
            if (!CollectionUtil.isEmpty(files)) {
                // 要打包的文件夹
                fs = files.toArray(new File[files.size()]);
            } else if (Objects.nonNull(destPath)) {
                File currentFile = new File(destPath);
                if (!currentFile.exists()) {
                    throw ExceptionResultEnum.ERROR.exception("待压缩的路径不存在");
                }
                fs = currentFile.listFiles();
            }

            // 遍历test文件夹下所有的文件、文件夹
            for (File f : fs) {
                if (f.isDirectory()) {
                    zipFile.addFolder(f.getPath(), parameters);
                } else {
                    zipFile.addFile(f, parameters);
                }
            }
        } catch (Exception e) {
            log.error(SystemConstant.LOG_ERROR, e);
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        }
    }
}
