package com.anjiplus.template.gaea.business.util;

import com.anji.plus.gaea.exception.BusinessExceptionBuilder;
import com.anjiplus.template.gaea.business.code.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Enumeration;
import java.util.zip.*;

/**
 * Created by raodeming on 2021/8/23.
 */
@Slf4j
public class FileUtil {

    //链接url下载图片
    public static void downloadPicture(String urlPath, String path) {
        URL url = null;
        try {
            url = new URL(urlPath);
            DataInputStream dataInputStream = new DataInputStream(url.openStream());

            FileOutputStream fileOutputStream = new FileOutputStream(path);
            ByteArrayOutputStream output = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            int length;

            while ((length = dataInputStream.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
            fileOutputStream.write(output.toByteArray());
            dataInputStream.close();
            fileOutputStream.close();
            log.info("链接下载图片：{}，临时路径：{}", urlPath, path);
        } catch (IOException e) {
            log.error("根据链接下载失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }


    /**
     * 复制文件
     *
     * @param source
     * @param dest
     * @throws IOException
     */
    public static void copyFileUsingFileChannels(File source, File dest) {
        FileChannel inputChannel = null;
        FileChannel outputChannel = null;
        try {
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            inputChannel = new FileInputStream(source).getChannel();
            outputChannel = new FileOutputStream(dest).getChannel();
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
        } catch (IOException e) {
            log.error("复制文件失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        } finally {
            try {
                inputChannel.close();
                outputChannel.close();
            } catch (IOException e) {
                log.error("", e);
                throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
            }
        }
    }

    /**
     * 复制文件
     *
     * @param source
     * @param dest
     * @throws IOException
     */
    public static void copyFileUsingFileChannels(String source, String dest) {
        copyFileUsingFileChannels(new File(source), new File(dest));
    }


    public static void WriteStringToFile(String filePath, String content) {
        try {
            //不存在创建文件
            File file = new File(filePath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            FileOutputStream outputStream = new FileOutputStream(filePath);
            OutputStreamWriter outputWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
            BufferedWriter bw = new BufferedWriter(outputWriter);
            bw.write(content);
            bw.close();
            outputWriter.close();
            outputStream.close();
        } catch (Exception e) {
            log.error("写入文件失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }


    /**
     * 根据文件读取文本文件内容
     *
     * @param file
     * @return
     */
    public static String readFile(File file) {
        BufferedReader reader = null;
        InputStreamReader isr = null;
        StringBuilder sbf = new StringBuilder();
        try {
            isr = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
            reader = new BufferedReader(isr);
            String tempStr;
            while ((tempStr = reader.readLine()) != null) {
                sbf.append(tempStr);
            }
            reader.close();
            return sbf.toString();
        } catch (IOException e) {
            log.error("读文件失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        } finally {
            if (null != isr) {
                try {
                    isr.close();
                } catch (IOException e) {
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e1.getMessage());
                }
            }
        }
    }

    /**
     * 根据文件路径读取文本文件内容
     *
     * @param filePath
     * @return
     */
    public static String readFile(String filePath) {
        File file = new File(filePath);
        return readFile(file);
    }

    static final int BUFFER = 8192;

    /**
     * 将文件夹压缩zip包
     *
     * @param srcPath
     * @param dstPath
     * @throws IOException
     */
    public static void compress(String srcPath, String dstPath) {
        File srcFile = new File(srcPath);
        File dstFile = new File(dstPath);

        FileOutputStream out = null;
        ZipOutputStream zipOut = null;
        try {
            out = new FileOutputStream(dstFile);
            CheckedOutputStream cos = new CheckedOutputStream(out, new CRC32());
            zipOut = new ZipOutputStream(cos, StandardCharsets.UTF_8);
            String baseDir = "";
            compress(srcFile, zipOut, baseDir);
        } catch (IOException e) {
            log.error("压缩文件夹失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        } finally {
            if (null != zipOut) {
                try {
                    zipOut.close();
                } catch (IOException e) {
                    log.error("", e);
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                }
                out = null;
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("", e);
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                }
            }
        }
    }

    private static void compress(File file, ZipOutputStream zipOut, String baseDir) {
        if (file.isDirectory()) {
            compressDirectory(file, zipOut, baseDir);
        } else {
            compressFile(file, zipOut, baseDir);
        }
    }

    /**
     * 压缩一个目录
     */
    private static void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) {
        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            compress(files[i], zipOut, baseDir + dir.getName() + "/");
        }
    }

    /**
     * 压缩一个文件
     */
    private static void compressFile(File file, ZipOutputStream zipOut, String baseDir) {
        if (!file.exists()) {
            return;
        }

        BufferedInputStream bis = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(file));
            ZipEntry entry = new ZipEntry(baseDir + file.getName());
            zipOut.putNextEntry(entry);
            int count;
            byte data[] = new byte[BUFFER];
            while ((count = bis.read(data, 0, BUFFER)) != -1) {
                zipOut.write(data, 0, count);
            }

        } catch (IOException e) {
            log.error("压缩文件夹失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        } finally {
            if (null != bis) {
                try {
                    bis.close();
                } catch (IOException e) {
                    log.error("", e);
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                }
            }
        }
    }

    public static void decompress(String zipFile, String dstPath) {
        try {
            decompress(new ZipFile(zipFile), dstPath);
        } catch (IOException e) {
            log.error("", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }

    public static void decompress(MultipartFile zipFile, String dstPath) {
        try {
            File dir = new File(dstPath);
            if (!dir.exists()){
                dir.mkdirs();
            }
            String path = dir.getPath();
            String absolutePath = dir.getAbsolutePath();
            File file = new File(dir.getAbsolutePath() + File.separator + zipFile.getOriginalFilename());
            zipFile.transferTo(file);
            decompress(new ZipFile(file), dstPath);
            //解压完删除
            file.delete();
        } catch (IOException e) {
            log.error("", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }

    /**
     * 解压zip
     *
     * @param zip
     * @param dstPath
     * @throws IOException
     */
    public static void decompress(ZipFile zip, String dstPath) {
        log.info("解压zip：{}，临时目录：{}", zip.getName(), dstPath);
        File pathFile = new File(dstPath);
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }
        try {

            for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                String zipEntryName = entry.getName();
                InputStream in = null;
                OutputStream out = null;
                try {
                    in = zip.getInputStream(entry);
                    String outPath = (dstPath + "/" + zipEntryName).replaceAll("\\*", "/");
                    ;
                    //判断路径是否存在,不存在则创建文件路径
                    File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                    if (!file.exists()) {
                        file.mkdirs();
                    }
                    //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                    if (new File(outPath).isDirectory()) {
                        continue;
                    }

                    out = new FileOutputStream(outPath);
                    byte[] buf1 = new byte[1024];
                    int len;
                    while ((len = in.read(buf1)) > 0) {
                        out.write(buf1, 0, len);
                    }
                } catch (IOException e) {
                    log.error("解压失败", e);
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                } finally {
                    if (null != in) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            log.error("", e);
                            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                        }
                    }

                    if (null != out) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            log.error("", e);
                            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                        }
                    }
                }
            }
            zip.close();
        } catch (IOException e) {
            log.error("解压失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }

    /**
     * 获取流文件
     * @param ins
     * @param file
     */
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            log.error("获取流文件失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }

    /**
     * 删除文件夹
     *
     * @param path
     */
    public static void delete(String path) {

        Path directory = Paths.get(path);
        try {
            Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
                    Files.delete(file); // this will work because it's always a File
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    Files.delete(dir); //this will work because Files in the directory are already deleted
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            log.error("删除文件失败", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
    }

    /**
     * byte 转file
     */
    public static File byte2File(byte[] buf, String filePath, String fileName){
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try{
            File dir = new File(filePath);
            if (!dir.exists()){
                dir.mkdirs();
            }
            file = new File(filePath + File.separator + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(buf);
        }catch (Exception e){
            log.error("", e);
            throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
        }
        finally{
            if (bos != null){
                try{
                    bos.close();
                }catch (IOException e){
                    log.error("", e);
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                }
            }
            if (fos != null){
                try{
                    fos.close();
                }catch (IOException e){
                    log.error("", e);
                    throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage());
                }
            }
        }
        return file;
    }


    public static void main(String[] args) throws Exception {
//        String targetFolderPath = "D:\\aa";
//        String rawZipFilePath = "D:\\aa.zip";
//        String newZipFilePath = "D:\\aa.zip";
//
//
//        //将目标目录的文件压缩成Zip文件
//        FileUtil.compress(targetFolderPath, newZipFilePath);
//
//        //将Zip文件解压缩到目标目录
//        FileUtil.decompress(rawZipFilePath, targetFolderPath);

//        FileUtil.downloadPicture("http://10.108.26.197:9095/file/download/fd20d563-00aa-45e2-b5db-aff951f814ec", "D:\\abc.png");


//        delete("D:\\aa");

    }


}
