package com.qmth.jkserver.common;

import com.qmth.jkserver.constant.SpringContextHolder;
import com.qmth.jkserver.constant.SystemConstant;
import com.qmth.jkserver.core.exception.JkServerException;
import com.qmth.jkserver.model.SysConfig;
import com.qmth.jkserver.service.CommonCacheService;
import com.qmth.jkserver.util.FileStoreUtil;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.StringJoiner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
 * zip 解压工具类
 *
 * @author tianjun
 */
public class UnZipUtils {
    private final static Logger log = LoggerFactory.getLogger(UnZipUtils.class);

    /**
     * @param zipFile 待解压的zip文件 	必须存在
     * @param destDir 目标目录		必须存在
     * @throws IOException
     * @throws ZipException
     */
    public static List<File> doUnZip(File zipFile, File destDir, String path) throws Exception {
        System.out.println("unzip:" + zipFile.getAbsolutePath());
        List<File> result = new LinkedList<File>();
        if (!zipFile.exists()) {
            throw new JkServerException("文件不存在," + zipFile.getAbsolutePath());
        }
        if (zipFile.isDirectory() || zipFile.getName().indexOf(SystemConstant.ZIP_PREFIX) == -1) {
            throw new JkServerException("zip文件格式错误");
        }
        if (!destDir.exists()) {
            destDir.mkdirs();
//            throw new JkServerException("指定目录不存在," + destDir.getAbsolutePath());
        }
//        CommonCacheService commonCacheService = SpringContextHolder.getBean(CommonCacheService.class);
//        SysConfig sysConfig = commonCacheService.addSysConfigCache(SystemConstant.SYS_CONFIG_KEY_CHARSETS);
        ZipFile zip = new ZipFile(zipFile, Charset.forName(SystemConstant.CHARSET_NAME));
        Enumeration entries = zip.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
            File target = new File(destDir.getAbsolutePath() + File.separator + entry.getName());
            if (entry.isDirectory()) {
                target.mkdirs();
            } else {
                File dir = target.getParentFile();
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                InputStream is = zip.getInputStream(entry);
                OutputStream os = new FileOutputStream(target);
                IOUtils.copy(is, os);
                os.flush();
                IOUtils.closeQuietly(os);
                IOUtils.closeQuietly(is);
                FileStoreUtil fileStoreConfig = SpringContextHolder.getBean(FileStoreUtil.class);
                //2020-12-19日加入上传到阿里云
                if (fileStoreConfig.workIsOss()) {
                    String md5 = DigestUtils.md5Hex(new FileInputStream(target));
                    if (!path.startsWith(fileStoreConfig.getStorageRoot()) && path.indexOf(fileStoreConfig.getStorageRoot()) != -1) {
                        path = path.substring(path.indexOf(fileStoreConfig.getStorageRoot()), path.length());
                    } else if (!path.startsWith(fileStoreConfig.getWorkRoot()) && path.indexOf(fileStoreConfig.getWorkRoot()) != -1) {
                        path = path.substring(path.indexOf(fileStoreConfig.getWorkRoot()), path.length());
                    }
                    StringJoiner stringJoiner = new StringJoiner("").add(fileStoreConfig.getWorkRoot()).add(File.separator).add(path).add(File.separator).add(entry.getName());
                    log.info("stringJoiner:{}", stringJoiner);
                    fileStoreConfig.ossUpload(stringJoiner.toString().replaceAll("\\\\", "/"), target, md5, fileStoreConfig.getWorkRoot());
                }
                result.add(target);
            }
        }
        zip.close();
        return result;
    }

    /**
     * 压缩指定路径的文件
     *
     * @param srcFilePath     待压缩文件路径
     * @param zipPathFileName zip文件全路径名
     * @param password        加密密码
     * @return
     */
    public static boolean zipFile(String srcFilePath, String zipPathFileName, String password) throws IOException {

        try {
            // 生成的压缩文件
            net.lingala.zip4j.core.ZipFile zipFile = new net.lingala.zip4j.core.ZipFile(zipPathFileName);
            ZipParameters parameters = new ZipParameters();
            // 压缩级别
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

            if (!StringUtils.isEmpty(password)) {
                parameters.setEncryptFiles(true);
                parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
                parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
                parameters.setPassword(password);
            }

            // 要打包的文件夹
            File currentFile = new File(srcFilePath);
            File[] fs = currentFile.listFiles();
            // 遍历test文件夹下所有的文件、文件夹
            for (File f : fs) {
                if (f.isDirectory()) {
                    zipFile.addFolder(f.getPath(), parameters);
                } else {
                    zipFile.addFile(f, parameters);
                }
            }
            return true;
        } catch (net.lingala.zip4j.exception.ZipException e) {
            e.printStackTrace();
            log.error("压缩文件【" + srcFilePath + "】到路径【" + zipPathFileName + "】失败：\n" + e.getMessage());
            return false;
        }
    }

    /**
     * @param zipFileFullName zip文件所在的路径名
     * @param filePath        解压到的路径
     * @param password        需要解压的密码
     * @return
     */
    public static boolean unZipFile(String zipFileFullName, String filePath, String password) {
        try {
            net.lingala.zip4j.core.ZipFile zipFile = new net.lingala.zip4j.core.ZipFile(zipFileFullName);
            // 如果解压需要密码
            if (StringUtils.isNotEmpty(password) && zipFile.isEncrypted()) {
                zipFile.setPassword(password);
            }
            zipFile.extractAll(filePath);
            return true;
        } catch (net.lingala.zip4j.exception.ZipException e) {
            e.printStackTrace();
            log.error("解压文件【" + zipFileFullName + "】到路径【" + filePath + "】失败：\n" + e.getMessage());
            return false;
        }
    }


    public static void main(String[] args) throws ZipException, IOException {
//        File dest = new File("E:\\KKKK");
//        if (!dest.exists()) {
//            dest.mkdirs();
//        }
//        File zip = new File("C:\\Users\\tianjun\\Desktop\\tj20171103.zip");
//        List<File> files = doUnZip(zip, dest);
//        System.out.println(files.size());
//        for (File file : files) {
//            System.out.println(file.getAbsolutePath());
//        }
    }
}
