package com.xiaoniu.subsystem.system.utils;


import com.xiaoniu.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * Mysql数据备份工具
 *
 * @USER: Cat Slave
 **/
@Slf4j
public class MysqlDataBackupUtil {


    // mysql bin目录路径
    public static final String MysqlPath = getMysqlPath();
    public static final boolean MysqlPathSystem = getMysqlSystem();

    private static final int BUFFER = 8192;


    // 根据系统判断使用mysql命令路径
    private static String getMysqlPath() {
        String osName = System.getProperty("os.name");
        if (Pattern.matches("Linux.*", osName)) {
            // linux读动态库，把动态库复制到/usr/lib下
            return "/usr/local/mysql/bin/";
        } else if (Pattern.matches("Windows.*", osName)) {
            // windows系统读动态库
            return "C:/genxiu/mysql/file/";
        }
        return null;
    }

    private static boolean getMysqlSystem() {
        String osName = System.getProperty("os.name");
        if (Pattern.matches("Linux.*", osName)) {
            // linux读动态库，把动态库复制到/usr/lib下
            return false;
        } else if (Pattern.matches("Windows.*", osName)) {
            // windows系统读动态库
            return true;
        }
        return true;
    }

    /**
     * 备份数据库db
     */
    // public static String dbBackUp(String ip, String port, String root, String pwd, String dbName, String fileName) throws Exception {
    //
    //     String mysqlPath = MysqlPath;
    //     String pathSql = mysqlPath + fileName;
    //     try {
    //         // 判断系统
    //         String osName = System.getProperties().getProperty("os.name");
    //         // 输出流文件
    //         File fileSql = createFile(mysqlPath, fileName);
    //         // 创建备份sql文件
    //         if (!fileSql.exists()) {
    //             fileSql.createNewFile();
    //         }
    //         // mysqldump -hlocalhost -uroot -p123456 db > /home/back.sql  整个库进行备份sql文件
    //         // mysqldump -hlocalhost -uroot -p123456 数据库名  数据表名 > /home/back.sql  单张表备份sql文件
    //         // mysqldump -h rm-hp3340490n5mw72tcto.mysql.huhehaote.rds.aliyuncs.com -u xuexinkaoshi_test -p'F6rX&N9ms2xWeTx@6QWtrEn' --opt --default-character-set=utf8 --hex-blob xuexinkaoshitest_db --skip-triggers --skip-lock-tables --set-gtid-purged=OFF  > /tmp/testdb.sql
    //         // StringBuilder sb = new StringBuilder();
    //
    //         // String sb =
    //         //         "C:/genxiu/mysql/bin/mysqldump -h" + ip + " -P" + port + " -u" + root + " -p"
    //         //                 + pwd + " " + dbName + " --ignore-table="+dbName+".tb_data_backupn > "  + pathSql;
    //         StringBuilder sb = new StringBuilder();
    //         sb.append("C:/genxiu/mysql/bin/mysqldump")
    //                 .append(" -h").append(ip)
    //                 .append(" -P").append(port)
    //                 .append(" -u").append(root)
    //                 .append(" -p").append(pwd)
    //                 .append(" ").append(dbName)
    //                 .append(" --ignore-table=").append(dbName).append(".tb_data_backupn")
    //                 // java中必须使用"-r"替代">"
    //                 .append(" < ").append(pathSql);
    //         Process process;
    //         // 判断系统
    //         if (osName.equals("Linux")) {
    //             BufferedReader bufferedReader = null;
    //             PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileSql), "utf8"));
    //             process = Runtime.getRuntime().exec("/usr/local/mysql/mysql/bin/" + sb);
    //             InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), "utf8");
    //             bufferedReader = new BufferedReader(inputStreamReader);
    //             String line;
    //             while ((line = bufferedReader.readLine()) != null) {
    //                 printWriter.println(line);
    //             }
    //             printWriter.flush();
    //             log.info("-==[ 备份结束！ ]==-");
    //         } else {
    //
    //             log.info("cmd命令为：" + "cmd /c " + sb);
    //             // 执行语句
    //             process =
    //                     Runtime.getRuntime().exec("cmd /c " + sb);
    //         }
    //         // 等待上述命令执行完毕后打印下面log
    //         process.waitFor();
    //         // 输出错误信息
    //         InputStream is = process.getErrorStream();
    //         // 读取
    //         InputStreamReader isr = new InputStreamReader(is, "gbk");
    //         log.info(isr.getEncoding());
    //         // 缓冲
    //         BufferedReader bufr = new BufferedReader(isr);
    //         String line = null;
    //         while ((line = bufr.readLine()) != null) {
    //             log.error("error:" + line);
    //         }
    //         isr.close();
    //         log.info("数据库备份结束，备份结果：{}", process.exitValue() == 0 ? "success" : "fail");
    //         return pathSql;
    //     } catch (IOException | InterruptedException e) {
    //         throw new ServiceException(e.getMessage());
    //     }
    // }

    /**
     * 备份数据库db
     */
    public static String dbBackUp(String ip, String port, String root, String pwd, String dbName, String fileName) {
        String mysqlPath = MysqlPath;
        String pathSql = mysqlPath + fileName;
        try {
            // 输出流文件
            File fileSql = createFile(mysqlPath, fileName);
            // 创建备份sql文件
            if (!fileSql.exists()) {
                fileSql.createNewFile();
            }
            // 创建ProcessBuilder，用于执行BAT脚本
            ProcessBuilder processBuilder = new ProcessBuilder("C:/genxiu/mysql/mysql-backup.bat",
                    ip, port, root, pwd, dbName, pathSql);
            // 启动进程
            Process process = processBuilder.start();
            // 获取输出流
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            // 读取输出
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            // 等待进程结束
            process.waitFor();
            log.info("数据库备份结束，备份结果：{}", process.exitValue() == 0 ? "success" : "fail");
            return pathSql;
        } catch (IOException | InterruptedException e) {
            throw new ServiceException(e.getMessage());
        }
    }


    /**
     * 恢复数据库
     * mysql -hlocalhost -uroot -proot dbname < /home/back.sql
     */
    // public static void dbRestore(String ip, String port, String root, String pwd, String dbName, String filePath) {
    //     StringBuilder sb = new StringBuilder();
    //     sb.append("C:/genxiu/mysql/binmysql")
    //             .append(" -h").append(ip)
    //             .append(" -P").append(port)
    //             .append(" -u").append(root)
    //             .append(" -p").append(pwd)
    //             .append(" ").append(dbName).append(" --default-character-set=utf8")
    //             // java中必须使用"-r"替代">"
    //             .append(" < ").append(filePath);
    //     log.info("cmd命令为：" + sb);
    //     Runtime runtime = Runtime.getRuntime();
    //     log.info("开始还原数据");
    //     // 判断系统
    //     String osName = System.getProperties().getProperty("os.name");
    //     Process process;
    //     try {
    //         // 判断系统
    //         if (osName.equals("Linux")) {
    //             process = runtime.exec(new String[]{"/bin/sh", "-c", "cd " + filePath + ";" + sb});
    //             log.info("-==[ 备份结束！ ]==-");
    //         } else {
    //             log.info("cmd命令为：" + "cmd /c " + sb);
    //             // 执行语句
    //             process = runtime.exec("cmd /c" + sb);
    //         }
    //         // 输出错误信息
    //         FileInputStream errorStream = (FileInputStream) process.getErrorStream();
    //         // 读取
    //         InputStreamReader isr = new InputStreamReader(errorStream, "gbk");
    //         log.info(isr.getEncoding());
    //         // 缓冲
    //         BufferedReader bufr = new BufferedReader(isr);
    //         String line = null;
    //         while ((line = bufr.readLine()) != null) {
    //             log.error("error:" + line);
    //         }
    //         isr.close();
    //         InputStream is = process.getInputStream();
    //         BufferedReader bf = new BufferedReader(new InputStreamReader(is, "utf8"));
    //         line = null;
    //         while ((line = bf.readLine()) != null) {
    //             log.error("error:" + line);
    //         }
    //         is.close();
    //         bf.close();
    //     } catch (IOException e) {
    //         throw new ServiceException(e.getMessage());
    //     }
    // }

    /**
     * 恢复数据库
     * mysql -hlocalhost -uroot -proot dbname < /home/back.sql
     */
    public static void dbRestore(String ip, String port, String root, String pwd, String dbName, String filePath) {
        try {
            log.info("获取数据：{},{},{},{}", root, pwd, dbName, filePath);
            // 创建ProcessBuilder，用于执行BAT脚本
            ProcessBuilder processBuilder = new ProcessBuilder("C:/genxiu/mysql/mysql-recover.bat",
                    ip, port, root, pwd, dbName, filePath);
            // 启动进程
            Process process = processBuilder.start();
            // 获取输出流
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            // 读取输出
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            // 等待进程结束
            process.waitFor();
        } catch (IOException | InterruptedException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    // 压缩文件
    public static void zipFile(String sourceFilePath, String zipFilePath) {
        try (FileInputStream fis = new FileInputStream(sourceFilePath);
             FileOutputStream fos = new FileOutputStream(zipFilePath);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            ZipEntry zipEntry = new ZipEntry(new File(sourceFilePath).getName());
            zos.putNextEntry(zipEntry);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }
            zos.closeEntry();
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    public static void zipFolder(String folderPath, String zipPath) throws IOException {
        Path folderPathObj = Paths.get(folderPath);
        Path zipPathObj = Paths.get(zipPath);
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zipPathObj))) {
            Files.walk(folderPathObj)
                    .filter(path -> !Files.isDirectory(path))
                    .forEach(path -> {
                        String filePath = folderPathObj.relativize(path).toString();
                        try {
                            zipOutputStream.putNextEntry(new ZipEntry(filePath));
                            Files.copy(path, zipOutputStream);
                            zipOutputStream.closeEntry();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
        }
    }

    // 解压文件
    public static String unzipFile(String zipFilePath, String destDirectory) {
        String name;
        try (FileInputStream fis = new FileInputStream(zipFilePath);
             ZipInputStream zis = new ZipInputStream(fis)) {
            ZipEntry zipEntry = zis.getNextEntry();
            name = zipEntry.getName();
            byte[] buffer = new byte[1024];
            while (zipEntry != null) {
                File newFile = newFile(destDirectory, zipEntry);
                try (FileOutputStream fos = new FileOutputStream(newFile)) {
                    int length;
                    while ((length = zis.read(buffer)) > 0) {
                        fos.write(buffer, 0, length);
                    }
                }
                zipEntry = zis.getNextEntry();
            }
            zis.closeEntry();
            return name;
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    private static File newFile(String destinationDir, ZipEntry zipEntry) throws IOException {
        File destFile = new File(destinationDir, zipEntry.getName());
        String destDirPath = destFile.getParent();
        if (destDirPath == null || !new File(destDirPath).exists()) {
            new File(destDirPath).mkdirs();
        }
        return destFile;
    }


    public static void downloadFile(String remoteFilePath, String localFilePath) {
        URL website = null;
        ReadableByteChannel rbc = null;
        FileOutputStream fos = null;
        try {
            website = new URL(remoteFilePath);
            rbc = Channels.newChannel(website.openStream());
            // 本地要存储的文件地址 例如：test.txt
            fos = new FileOutputStream(localFilePath);
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (rbc != null) {
                try {
                    rbc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public static void downloadAndZip(List<String> urls, String zipFilePath) throws IOException {
        // 创建zip输出流
        ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath));

        for (String url : urls) {
            // 从URL下载文件
            String fileName = url.substring(url.lastIndexOf("/") + 1);
            // InputStream inputStream = new URL(url).openStream();
            InputStream inputStream = new FileInputStream(new File(url));

            // 将文件添加到zip输出流
            zipOut.putNextEntry(new ZipEntry(fileName));

            // 写入文件内容
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                zipOut.write(buffer, 0, length);
            }

            // 关闭当前文件流
            inputStream.close();
            zipOut.closeEntry();
        }

        // 关闭zip输出流
        zipOut.close();
    }

    /**
     * 创建临时文件
     *
     * @param filePaht 文件目录
     * @param fileName 文件名称
     * @return {@link File}
     * @throws IOException ioexception
     */
    public static File createFile(String filePaht, String fileName) {
        File tempFile = new File(filePaht, fileName);
        if (!tempFile.getParentFile().exists()) {
            tempFile.getParentFile().mkdirs();
        }
        if (!tempFile.exists()) {
            try {
                tempFile.createNewFile();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
        return tempFile;
    }

    /**
     * 删除单个文件
     *
     * @param pathName 删除文件路径名
     * @return
     */
    public static boolean deleteFiles(String pathName) {
        boolean flag = false;
        // 根据路径创建文件对象
        File file = new File(pathName);
        // 路径是个文件且不为空时删除文件
        if (file.isFile() && file.exists()) {
            flag = file.delete();
        }
        // 删除失败时，返回false
        if (!flag) {
            log.error("文件：" + pathName + ",删除失败");
        }
        return flag;
    }

} 