package com.yfd.platform.utils;

import it.sauronsoftware.ftp4j.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 *
 * 穿透TLS上传FTP
 */
@Slf4j
@Service
public class TLSFTPUtils {

    private static String remotePath = "/DebugLog";

    FTPClient client = new FTPClient();

    SSLContext sslContext = null;

    TrustManager[] trustManager = new TrustManager[] { new X509TrustManager() {

        public void checkClientTrusted(X509Certificate[] chain,
                                       String authType) throws CertificateException {
            // TODO Auto-generated method stub

        }

        public void checkServerTrusted(X509Certificate[] chain,
                                       String authType) throws CertificateException {
            // TODO Auto-generated method stub

        }

        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }

    } };

    /**
     * ftp是否已连接
     * @throws IOException
     *
     */
    public boolean isConnected() {
        if (client.isConnected()) {
            return true;
        }
        return false;
    }

    public boolean connect(String hostname, String username, String password,int port)  {
        try {
            sslContext = SSLContext.getInstance("SSL");
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage());
            log.error("SSL");
            return false;
        }
        try {
            sslContext.init(null, trustManager, new SecureRandom());
        } catch (KeyManagementException e) {
            log.error(e.getMessage());
            log.error("init");
            return false;
        }
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        client.setSSLSocketFactory(sslSocketFactory);
        client.setSecurity(FTPClient.SECURITY_FTPS);
        client.setPassive(true);//设置被动
        client.setType(FTPClient.TYPE_BINARY);
        client.setCharset("gbk");
        try {
            client.connect(hostname,port);
        } catch (IOException | FTPIllegalReplyException | FTPException e) {
            log.error(e.getMessage());;
            log.error("connect");
            return false;
        }
        log.info("连接"+hostname+"成功！"+client.toString());
        try {
            client.login(username, password);
        } catch (IOException | FTPIllegalReplyException | FTPException e) {
            log.error(e.getMessage());;
            log.error("login");
            return false;
        }
        log.info("登录"+hostname+"成功！"+client.toString());

        return true;
    }

    /**
     * 上传文件或目录
     *
     * @param dir
     *            目标文件
     * @param del
     *            是否删除源文件，默认为false
     *            文件或目录对象数组
     * @throws Exception
     */
    public void upload(String dir,boolean del, File... files) throws Exception {
        if (StringUtils.isEmpty(dir) || files == null) {
            return;
        }

        try {
            boolean b = isDirExist(dir);
            if(!b){
                mkdirs(dir); // 创建文件夹
            }
            for (File file : files) {
                if(file == null){
                    log.error("文件不存在！！");
                    continue;
                }
                if (file.isDirectory()) { // 上传目录
                    uploadFolder(getURL(dir), file, del);
                } else {
                    String current2 = client.currentDirectory();
                    log.info(current2);
                    //查询ftp服务器里的图片列表
                    FTPFile[] files2 = client.list();
                    if(files2 != null){
                        log.info(file.getName());
                        for (FTPFile ftpFile:files2){
                            if (ftpFile.getName().equals(file.getName())){
                                String remoteFilePath = dir + "/" + file.getName();
                                log.info("=================remoteFilePath==============="+remoteFilePath);
                                client.deleteFile(remoteFilePath);
                                break;
                            }
                        }
                        log.info("从0上传:"+file.getName());
                        try {
                            client.upload(file);
                            log.info("从0上传上传成功！");
                        }catch (Exception e){
                            log.info("从0上传上传失败！");
                            log.error(e.getMessage());
                        }
                    }else {
                        client.upload(file);
                    }

                }
            }
        } finally {
         logout();
        }
    }


    /**
     * 上传文件或目录
     *
     * @param dir
     *            目标文件
     * @param files
     *            文件或目录对象数组
     * @throws Exception
     */
    public void upload(String dir, File... files) throws Exception {
        log.info("开始执行upload");
        upload(dir, false, files);
        log.info("upload执行成功");
    }
    /**
     * 上传文件或目录
     *
     * @param dir
     *            目标文件
     * @param del
     *            是否删除源文件，默认为false
     *            文件或目录路径数组
     * @throws Exception
     */
    public void upload(String dir, boolean del, String... paths)
            throws Exception {
        if (dir==null || paths == null || paths.length ==0) {
            return;
        }
        File[] files = new File[paths.length];
        for (int i = 0; i < paths.length; i++) {
            files[i] = new File(paths[i]);
        }
        upload(dir, del, files);
    }
    /**
     * 上传文件或目录
     *
     * @param dir
     *            远程目标文件
     * @param paths
     *            文件或目录路径数组
     * @throws Exception
     */
    public void upload(String dir, String... paths) throws Exception {
        upload(dir, false, paths);
    }
    /**
     * 上传目录
     *
     * @param parentUrl
     *            父节点URL
     * @param file
     *            目录
     * @throws Exception
     */
    private void uploadFolder( URL parentUrl, File file,
                               boolean del) throws Exception {
        client.changeDirectory(parentUrl.getPath());
        String dir = file.getName(); // 当前目录名称
        URL url = getURL(parentUrl, dir);
        if (!exists(url.getPath())) { // 判断当前目录是否存在
            client.createDirectory(dir); // 创建目录
        }
        client.changeDirectory(dir);
        File[] files = file.listFiles(); // 获取当前文件夹所有文件及目录
        for (int i = 0; i < files.length; i++) {
            file = files[i];
            if (file.isDirectory()) { // 如果是目录，则递归上传
                uploadFolder( url, file, del);
            } else { // 如果是文件，直接上传
//            client.changeDirectory(url.getPath());
                String current2 = client.currentDirectory();
                log.info(current2);
                FTPFile[] files2 = client.list();
                FTPFile remoteFtpFile=null;
                boolean flag=false;
                for (FTPFile ftpFile:files2){
                    if (ftpFile.getName().equals(file.getName())){
                        flag=true;
                        remoteFtpFile=ftpFile;
                        break;
                    }
                }
                if (flag){
                    log.info("断点续传");
                    long remote_file_size=remoteFtpFile.getSize();
                    client.upload(file,remote_file_size);
                    log.debug("AbstractFtpEndpointComponent  upload  continue upload file success");

                }else {
                    log.info("从0上传");
                    client.upload(file);
                }
                if (del){ // 删除源文件
                    file.delete();
                }
            }
        }
    }
    /**
     * 删除文件或目录
     *
     *            文件或目录数组
     * @throws Exception
     */
    public void delete(String... dirs) throws Exception {
        if (dirs == null || dirs.length ==0) {
            return;
        }
        try {
            int type = -1;
            for (String dir : dirs) {
                client.changeDirectory("/"); // 切换至根目录
                type = getFileType(dir); // 获取当前类型
                if (type == 0) { // 删除文件
                    client.deleteFile(dir);
                } else if (type == 1) { // 删除目录
                    deleteFolder(client, getURL(dir));
                }
            }
        } finally {
//         logout();
        }
    }
    /**
     * 删除目录
     *
     * @param client
     *            FTP客户端对象
     * @param url
     *            FTP URL
     * @throws Exception
     */
    private void deleteFolder(FTPClient client, URL url) throws Exception {
        String path = url.getPath();
        client.changeDirectory(path);
        FTPFile[] files = client.list();
        String name = null;
        for (FTPFile file : files) {
            name = file.getName();
            // 排除隐藏目录
            if (".".equals(name) || "..".equals(name)) {
                continue;
            }
            if (file.getType() == FTPFile.TYPE_DIRECTORY) { // 递归删除子目录
                deleteFolder(client, getURL(url, file.getName()));
            } else if (file.getType() == FTPFile.TYPE_FILE) { // 删除文件
                client.deleteFile(file.getName());
            }
        }
        client.changeDirectoryUp();
        client.deleteDirectory(url.getPath()); // 删除当前目录
    }
    /**
     * 下载文件或目录
     *
     * @param localDir
     *            本地存储目录
     * @param dirs
     *            文件或者目录
     * @throws Exception
     */
    public void download(String localDir, String... dirs) throws Exception {
        if (dirs==null ||dirs.length ==0) {
            return;
        }
        try {
            File folder = new File(localDir);
            if (!folder.exists()) { // 如果本地文件夹不存在，则创建
                folder.mkdirs();
            }
            String localPath = null;
            for (String dir : dirs) {
                /*int i = dir.lastIndexOf("/");
                String subDir = dir.substring(0,i);
                String subFileName = dir.substring(i+1,dir.length());*/
                client.changeDirectory("/"); // 切换至根目录
                //client.changeDirectory(subDir);
                File newFile = new File(dir);  //FTP文件
                localPath = localDir + "/" + newFile.getName();
                File file=null;   //本地文件  = new File(localPath)
                File[] files = folder.listFiles();
                boolean flag=false;
                for (File fileTemp:files) {
                    if (fileTemp.getName().equals(newFile.getName())) {
                        flag = true;
                        file = fileTemp;
                        break;
                    }
                }
                if (flag){
                    log.info("断点续传");
                    long local_file_size=file.length();
                    log.info("从"+local_file_size+"开始");
                    //client.setType(FTPClient.TYPE_BINARY);
                    client.download(dir,file,local_file_size);
                }else {
                    log.info("从0下载");
                    file = new File(localPath);
                    //client.setType(FTPClient.TYPE_BINARY);
                    client.download(dir, file);
                }
            }
        } finally {
//         logout();
        }
    }
    /**
     * 下载文件夹
     *
     * @param client
     *            FTP客户端对象
     * @param url
     *            FTP URL
     * @param localDir
     *            本地存储目录
     * @throws Exception
     */
    private void downloadFolder(FTPClient client, URL url, String localDir)
            throws Exception {
        String path = url.getPath();
        client.changeDirectory(path);
        // 在本地创建当前下载的文件夹
        File folder = new File(localDir + "/" + new File(path).getName());
        if (!folder.exists()) {
            folder.mkdirs();
        }
        localDir = folder.getAbsolutePath();
        FTPFile[] files = client.list();
        String name = null;
        for (FTPFile file : files) {
            name = file.getName();
            // 排除隐藏目录
            if (".".equals(name) || "..".equals(name)) {
                continue;
            }
            if (file.getType() == FTPFile.TYPE_DIRECTORY) { // 递归下载子目录
                downloadFolder(client, getURL(url, file.getName()), localDir);
            } else if (file.getType() == FTPFile.TYPE_FILE) { // 下载文件
                File localFolder = new File(localDir);
                File file1 = null;
                File[] localfiles = localFolder.listFiles();
                boolean flag=false;
                for (File fileTemp:localfiles) {
                    if (fileTemp.getName().equals(file.getName())) {
                        flag = true;
                        file1 = fileTemp;
                        break;
                    }
                }
                if (flag){
                    log.info("断点续传");
                    long local_file_size=file1.length();
                    log.info("从"+local_file_size+"开始");
                    client.download(name,file1,local_file_size);
                }else {
                    log.info("从0下载");
                    file1 = new File(localDir + "/" + name);
                    client.download(name, file1);
                }

            }
        }
        client.changeDirectoryUp();
    }

    //   /**
//    * 获取目录下所有文件
//    *
//    * @param dir
//    *            远程目标文件
//    * @return
//    * @throws Exception
//    */
//   public String[] list(String dir) throws Exception {
    //FTPClient client = null;
//      try {
    //client = getClient();
//         client.changeDirectory(dir);
//         String[] values = client.listNames();
//         if (values != null) {
//            // 将文件排序(忽略大小写)
//            Arrays.sort(values, String::compareToIgnoreCase);
//         }
//         return values;
//      } catch(FTPException fe) {
//         // 忽略文件夹不存在的情况
//         String mark = "code=550";
//         if (!fe.toString().contains(mark)) {
//            throw fe;
//         }
//      } finally {
//         logout();
//      }
//      return new String[0];
//   }


    /**
     * 创建目录
     *            FTP客户端对象
     * @param dir
     *            目录
     * @throws Exception
     */
    private void mkdirs(String dir) throws Exception {
        if (dir == null || dir.equals("")) {
            return;
        }
        dir = FTPPathToolkit.formatPathFTP(dir);
        dir = dir.replace("//", "/");
        String[] dirs = dir.split("/");
        String path = "/";
        for (int i = 0; i < dirs.length; i++) {
            if(i == 0){
                path += dirs[i];
            }else {
                path  =path + "/" +  dirs[i];
            }

            if (!isDirExist(path)) {
                log.info("创建"+path+"目录");
                client.createDirectory(path);// 创建目录
                log.info("创建"+path+"目录成功");
            }
        }
        client.changeDirectory(path);// 进入创建的目录
    }


    /**
     * 获取FTP目录
     *
     * @param url
     *            原FTP目录
     * @param dir
     *            目录
     * @return
     * @throws Exception
     */
    private URL getURL(URL url, String dir) throws Exception {
        String path = url.getPath();
        if (!path.endsWith("/") && !path.endsWith("//")) {
            path += "/";
        }
        dir = dir.replace("//", "/");
        if (dir.startsWith("/")) {
            dir = dir.substring(1);
        }
        path += dir;
        return new URL(url, path);
    }
    /**
     * 获取FTP目录
     *
     * @param dir
     *            目录
     * @return
     * @throws Exception
     */
    private URL getURL(String dir) throws Exception {
        if (dir.startsWith("/")) {
            dir = dir.substring(1);
        }
        return getURL(new URL("http://8.8.8.8"), dir);
    }

    /**
     * 判断文件或目录是否存在
     *
     *            FTP客户端对象
     * @param dir
     *            文件或目录
     * @return
     * @throws Exception
     */
    private boolean exists(String dir) throws Exception {
        return getFileType(dir) != -1;

    }

    //检查目录是否存在
    private boolean isDirExist(String dir) {
        try {
//            client.changeDirectoryUp();
//            client.changeDirectoryUp();
            log.info("当前目录：" +client.currentDirectory()+ "==========进入目录" + dir);
            client.changeDirectory(dir);
            log.info("进入目录 "+ dir +"成功");
        } catch (Exception e) {
            log.info(dir+"目录不存在");
            return false;
        }
        return true;
    }


    /**
     * 判断当前为文件还是目录
     *
     *            FTP客户端对象
     * @param dir
     *            文件或目录
     * @return -1、文件或目录不存在 0、文件 1、目录
     */
    private int getFileType( String dir) {
        FTPFile[] files = null;
        try {
            files = client.list(dir);

        } catch (Exception e) {
            return -1;
        }
        if (files.length > 1) {
            return FTPFile.TYPE_DIRECTORY;
        } else if (files.length == 1) {
            FTPFile f = files[0];
            if (f.getType() == FTPFile.TYPE_DIRECTORY) {
                return FTPFile.TYPE_DIRECTORY;
            }
            String path = dir + "/" + f.getName();
            try {
                int len = client.list(path).length;
                if (len == 1) {
                    return FTPFile.TYPE_DIRECTORY;
                } else {
                    return FTPFile.TYPE_FILE;
                }
            } catch (Exception e) {
                return FTPFile.TYPE_FILE;
            }
        } else {
            try {
                client.changeDirectory(dir);
                client.changeDirectoryUp();
                return FTPFile.TYPE_DIRECTORY;
            } catch (Exception e) {
                return -1;
            }
        }
    }


    /**
     * 注销客户端连接
     *
     * @param
     *
     * @throws Exception
     */
    public void logout()  {
        if (client != null) {
            try {
                // 有些FTP服务器未实现此功能，若未实现则会出错
                client.logout(); // 退出登录
            } catch (Exception fe) {

            } finally {
                if (client.isConnected()) { // 断开连接
                    try {
                        client.disconnect(true);
                    } catch (IOException | FTPIllegalReplyException | FTPException e) {
                        log.error(e.getMessage());;
                        log.error("退出异常");
                    }
                }
            }
        }
    }


    /**
     * 断开与远程服务器的连接
     * @throws IOException
     *
     */
    public void disconnect() {
        if (client.isConnected()) {
            try {
                client.disconnect(true);
            } catch (IOException | FTPIllegalReplyException | FTPException e) {
                log.error(e.getMessage());;
                log.error("退出异常");
            }
        }
    }


}


