package cn.pluss.platform.util;


import cn.pluss.platform.exception.MsgException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.util.zip.GZIPInputStream;

/**
 * ftp文件操作工具类
 */
public class FtpUtils {

//    // ftp服务器地址
//    public String hostname = "119.254.93.57";
//
//    // ftp服务器端口号默认为21
//    public Integer port = 22221;
//
//    // ftp登录账号
//    public String username = "rscy";
//
//    // ftp登录密码fileName
//    public String password = "gS4*F&o51KhA";
//
//    public String basePath = "onlpay/";

    public static FTPClient ftpClient = null;

    /**
     * 本地字符编码
     **/
    private static String localCharset = "GBK";

    /**
     * FTP协议里面，规定文件名编码为iso-8859-1
     **/
    private static String serverCharset = "ISO-8859-1";

    /**
     * UTF-8字符编码
     **/
    private static final String CHARSET_UTF8 = "UTF-8";

    /**
     * OPTS UTF8字符串常量
     **/
    private static final String OPTS_UTF8 = "OPTS UTF8";

    /**
     * 设置缓冲区大小4M
     **/
    private static final int BUFFER_SIZE = 1024 * 1024 * 4;

    /**
     * 下载该目录下所有文件到本地
     *
     * @param ftpPath  FTP服务器上的相对路径，例如：test/123
     * @param savePath 保存文件到本地的路径，例如：D:/test
     * @return 成功返回true，否则返回false
     */
    public static boolean  downloadFiles(String prefixPath,String ftpPath, String savePath,String hostname,Integer port,String username,String password) {
        // 登录
        login(hostname, port, username, password);
        if (ftpClient != null) {
            try {
                String path = changeEncoding(prefixPath + ftpPath);
                // 判断是否存在该目录
                if (!ftpClient.changeWorkingDirectory(path)) {
                    return Boolean.FALSE;
                }
                ftpClient.enterLocalPassiveMode();  // 设置被动模式，开通一个端口来传输数据
                String[] fs = ftpClient.listNames();
                // 判断该目录下是否有文件
                if (fs == null || fs.length == 0) {
                    return Boolean.FALSE;
                }
                for (String ff : fs) {
                    String ftpName = new String(ff.getBytes(serverCharset), localCharset);
                    File file = new File(savePath + '/' + ftpName);
                    try (OutputStream os = new FileOutputStream(file)) {
                        ftpClient.retrieveFile(ff, os);
                    } catch (Exception e) {
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                closeConnect();
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 连接FTP服务器
     *
     * @param address  地址，如：127.0.0.1
     * @param port     端口，如：21
     * @param username 用户名，如：root
     * @param password 密码，如：root
     */
    private static void login(String address, int port, String username, String password) {
        ftpClient = new FTPClient();
        try {
            ftpClient.connect(address, port);
            ftpClient.login(username, password);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            //限制缓冲区大小
            ftpClient.setBufferSize(BUFFER_SIZE);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                closeConnect();
                MsgException.throwException("FTP服务器连接失败");
            }
        } catch (Exception e) {
            MsgException.throwException("FTP登录失败");
        }
    }


    /**
     * FTP服务器路径编码转换
     *
     * @param ftpPath FTP服务器路径
     * @return String
     */
    private static  String changeEncoding(String ftpPath) {
        String directory = null;
        try {
            if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
                localCharset = CHARSET_UTF8;
            }
            directory = new String(ftpPath.getBytes(localCharset), serverCharset);
        } catch (Exception e) {
            MsgException.throwException("路径编码转换失败");
        }
        return directory;
    }

    /**
     * 关闭FTP连接
     */
    private static void closeConnect() {
        if (ftpClient != null && ftpClient.isConnected()) {
            try {
                ftpClient.logout();
                ftpClient.disconnect();
            } catch (IOException e) {
//                logger.error("关闭FTP连接失败", e);
                MsgException.throwException("关闭FTP连接失败");
            }
        }
    }


    /**
     * 检查指定目录下是否含有指定文件
     *
     * @param ftpPath  FTP服务器文件相对路径，例如：test/123
     * @param fileName 要下载的文件名，例如：test.txt
     * @return 成功返回true，否则返回false
     */
    public boolean checkFileInFtp(String prefixPath,String ftpPath, String fileName,String hostname,Integer port,String username,String password) {
        // 登录
        login(hostname, port, username, password);
        if (ftpClient != null) {
            try {
                String path = changeEncoding(prefixPath + ftpPath);
                // 判断是否存在该目录
                if (!ftpClient.changeWorkingDirectory(path)) {
                    //logger.error(basePath + ftpPath + DIR_NOT_EXIST);
                    return Boolean.FALSE;
                }
                ftpClient.enterLocalPassiveMode();  // 设置被动模式，开通一个端口来传输数据
                String[] fs = ftpClient.listNames();
                // 判断该目录下是否有文件
                if (fs == null || fs.length == 0) {
                    return Boolean.FALSE;
                }
                for (String ff : fs) {
                    String ftpName = new String(ff.getBytes(serverCharset), localCharset);
                    if (ftpName.equals(fileName)) {
                        return Boolean.TRUE;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                closeConnect();
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 下载该目录下所有文件到本地 根据实际需要修改执行逻辑
     *
     * @param ftpPath  FTP服务器上的相对路径，例如：test/123
     * @param savePath 保存文件到本地的路径，例如：D:/test
     * @return 成功返回true，否则返回false
     */
//    public Map<String, Object> downLoadTableFile(String ftpPath, String savePath) {
//        // 登录
//        login(hostname, port, username, password);
//        Map<String, Object> resultMap = new HashMap<>();
//        if (ftpClient != null) {
//            try {
//                String path = changeEncoding(basePath + "/" + ftpPath);
//                // 判断是否存在该目录
//                if (!ftpClient.changeWorkingDirectory(path)) {
//                    System.out.println("12================>"+basePath + "/" + ftpPath + DIR_NOT_EXIST);
//                    //logger.error(basePath + "/" + ftpPath + DIR_NOT_EXIST);
//                    resultMap.put("result", false);
//                    return resultMap;
//                }
//                ftpClient.enterLocalPassiveMode();  // 设置被动模式，开通一个端口来传输数据
//                String[] fs = ftpClient.listNames();
//                // 判断该目录下是否有文件
//                if (fs == null || fs.length == 0) {
////                    logger.error(basePath + "/" + ftpPath + DIR_CONTAINS_NO_FILE);
//                    System.out.println("12================>"+basePath + "/" + ftpPath + DIR_CONTAINS_NO_FILE);
//                    resultMap.put("result", false);
//                    return resultMap;
//                }
//                List<String> tableFileNameList = new ArrayList<>();
//                //根据表名创建文件夹
//                String tableDirName = savePath + "/" + ftpPath;
//                File tableDirs=new File(tableDirName);
//                if(!tableDirs.exists()){
//                    tableDirs.mkdirs();
//                }
//                for (String ff : fs) {
//                    String ftpName = new String(ff.getBytes(serverCharset), localCharset);
//                    File file = new File(tableDirName + "/" + ftpName);
//                    //存储文件名导入时使用
//                    tableFileNameList.add(tableDirName + "/" + ftpName);
//                    try (OutputStream os = new FileOutputStream(file)) {
//                        ftpClient.retrieveFile(ff, os);
//                    } catch (Exception e) {
//                        System.out.println("13================>"+e.getMessage());
////                        logger.error(e.getMessage(), e);
//                    }
//                }
//                resultMap.put("fileNameList", tableFileNameList);
//                resultMap.put("result", true);
//                return resultMap;
//            } catch (IOException e) {
//                System.out.println("13================>下载文件失败");
////                logger.error("下载文件失败", e);
//            } finally {
//                closeConnect();
//            }
//        }
//        resultMap.put("result", false);
//        return resultMap;
//    }


    /**
     *  Ø  目录示例：/onlpay/20200701/ 线上交易对帐文件每天1个文件夹，命名方式为8位年月日
     *  Ø  交易对帐文件tran_ROX00000000****_20200701.cvs.gz
     *  Ø  出款预对帐文件pre_balance_ROX00000000****_20200701.txt.gz
     *  Ø  出款终对帐文件last_balance_ROX00000000****_20200701.txt.gz
     *  Ø  差错对账文件prev_error_ROX00000000****_20200512.cvs.gz
     *  /onlpay/20210202/pre_balance_ROX000000002983_20210202.txt.gz
     */
//    public static void main(String[] args) throws IOException {
//        FtpUtils ftp = new FtpUtils();
//        ftp.downloadFiles("20210202/","E:\\crystal\\ftp\\file");
//
//        String filePath = "E:\\crystal\\ftp\\file\\";
//        String fileName = "pre_balance_ROX000000002983_20210202.txt.gz";
//        FileInputStream fileInputStream = new FileInputStream(filePath + fileName);
//        //解凍する
//        GZIPInputStream Zin = new GZIPInputStream(fileInputStream);
//        File outdir = new File(filePath);
//        extractFile(Zin, outdir, "aaa.txt");
//    }

    public static void extractFile(String fileName,String filePath,String outFileName) throws IOException {
        FileInputStream fileInputStream = new FileInputStream(filePath + File.separator +fileName);
        //解凍する
        GZIPInputStream in = new GZIPInputStream(fileInputStream);
        File outdir = new File(filePath);
        byte[] buffer = new byte[BUFFER_SIZE];
        BufferedOutputStream out = new BufferedOutputStream(
                new FileOutputStream(new File(outdir, outFileName)));
        int count = -1;
        while ((count = in.read(buffer)) != -1) {
            out.write(buffer, 0, count);
        }
        out.close();
    }


}
