package com.bcxin.signature.util.ftp;

import com.bcxin.signature.config.FileWriteConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * <b> ftp客户端 </b>
 * @author ZXF
 * @create 2023/07/07 0007 13:51
 * @version
 * @注意事项 </b>
 */
@Slf4j
public class FtpWriteConnection {
    private static final Logger logger = LoggerFactory.getLogger(FtpWriteConnection.class);

    private FTPClient ftp = new FTPClient();

    private boolean is_connected = false;

    /**
     * 构造函数
     */
    public FtpWriteConnection() {
        is_connected = false;
        ftp.setDefaultTimeout(FileWriteConfig.defaultTimeoutSecond * 1000);
        ftp.setConnectTimeout(FileWriteConfig.connectTimeoutSecond * 1000);
        ftp.setDataTimeout(FileWriteConfig.dataTimeoutSecond * 1000);
        try {
            initConnect(FileWriteConfig.getHost(), FileWriteConfig.getPort(), FileWriteConfig.getUserName(), FileWriteConfig.getPassword());
        } catch (IOException e) {
            logger.error("FtpWriteConnection 初始化发生异常", e);
        }
    }

    /**
     * 初始化连接
     *
     * @param host
     * @param port
     * @param user
     * @param password
     * @throws IOException
     */
    private void initConnect(String host, int port, String user, String password) throws IOException {
        try {
            if(!ftp.isConnected()){
                ftp.connect(host, port);
            }
        } catch (UnknownHostException ex) {
            throw new IOException("Can't find FTP server '" + host + "'");
        }
        //被动模式
        ftp.enterLocalPassiveMode();
        int reply = ftp.getReplyCode();//220 连接成功
        if (!FTPReply.isPositiveCompletion(reply)) {
            disconnect();
            throw new IOException("Can't connect to server '" + host + "'");

        }
        if (!ftp.login(user, password)) {
            is_connected = false;
            disconnect();
            throw new IOException("Can't login to server '" + host + "'");
        } else {
            is_connected = true;
        }
    }

    public static boolean hasChineseUsingRegex(String str) {
        return str.matches(".*[\u4e00-\u9fa5]+.*");
    }

    public boolean uploadBase64(String path, String ftpFileName, String base64Content) throws IOException {
        boolean is = false;
        // 检查Base64内容是否为空
        if (base64Content == null || base64Content.isEmpty()) {
            logger.error("fail to upload out file({}) with base64Content empty", ftpFileName);
            throw new IOException("Can't upload. The base64 content is empty.");
        }
        // 转换路径和文件名，防止设置工作路径出错
        conv(path, ftpFileName);
        if (hasChineseUsingRegex(ftpFileName)) {
            logger.error("fail to upload out file({}) with hasChineseUsingRegex", ftpFileName);
            return false;
        }

        if (StringUtils.isNotEmpty(path)) {
            path = new String(path.getBytes("GBK"), "iso-8859-1");
            // 设置工作路径
            setWorkingDirectory(path);
        }
        ftpFileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");

        // 将Base64字符串解码为字节数组
        byte[] decodedBytes = base64Content.getBytes();
        if(!ftp.isConnected()) {
            initConnect(FileWriteConfig.getHost(), FileWriteConfig.getPort(), FileWriteConfig.getUserName(),
                    FileWriteConfig.getPassword());
        }
        // 上传
        try (InputStream in = new ByteArrayInputStream(decodedBytes)) {
            String filePath = path + "/" + ftpFileName;
            filePath = filePath.replace("\\", "/");
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            // 保存文件
            is = ftp.storeFile(filePath, in);

            logger.error("success to upload out file(rt:{}-size={}byte):{}", is, decodedBytes.length,ftpFileName);
        } catch (Exception e) {
            logger.error("fail to upload out file uploadBase64 exception:{}-{}", path, ftpFileName, e);
        }

        return is;
    }

    private static void conv(String path,String ftpFileName){
        ftpFileName = ftpFileName.startsWith("/")?ftpFileName:"/"+ftpFileName;
        Path sourcePath = Paths.get(path+ftpFileName);
        if(sourcePath.getParent() !=null){
            path = sourcePath.getParent().toAbsolutePath().toString();
        }
        ftpFileName = sourcePath.getFileName().toString();
    }

    /**
     * 获取ftp目录下所有最近5分钟内生成的文件的文件名，返回文件名列表
     *
     * @param path ftp操作目录
     * @return 最近5分钟内生成的文件名列表
     * @throws IOException
     */
    public List<String> fileNames(String path,String keywork) throws IOException {
        if(StringUtils.isEmpty(keywork)){
            keywork = "IN-";
        }

        StringBuilder sb = new StringBuilder();
        try {
            if (StringUtils.isNotEmpty(path)) {
                path = new String(path.getBytes("GBK"), "iso-8859-1");
                sb.append("=======>获取ftp目录下所有文件业务节点：001<=======");
                // 设置工作路径
                setWorkingDirectory(path);
            }
            sb.append("=======>获取ftp目录下所有文件业务,ftp路径：" + path + ",关键字：" + keywork + "<=======");

            List<String> recentFiles = new ArrayList<>();
            FTPFile[] files = ftp.listFiles();
            sb.append(String.format("=======>获取ftp目录下所有文件业务节点：003<=======:获取ftp目录下所有文件的数量 size=%s",files.length));
            long currentTime = System.currentTimeMillis();
            long fiveMinutesAgo = currentTime - (5 * 60 * 1000); // 5 minutes ago in milliseconds
            for (FTPFile file : files) {

                //转utc 时间加8小时
                Long fileTime = file.getTimestamp().getTimeInMillis() + file.getTimestamp().getTimeZone().getOffset(0);
                if (file.isFile() && fileTime >= fiveMinutesAgo && file.getName().startsWith(keywork)) {
                    sb.append(String.format("=======>获取ftp目录下所有文件业务有效文件名：%s<=======",file.getName()));
                    recentFiles.add(file.getName());
                }else{
                    sb.append(String.format("=======>获取ftp目录下所有文件业务有效文件名-->不符合：%s<=======",file.getName()));
                }
            }

            sb.append(String.format("=======>获取ftp目录下所有最近5分钟内生成的文件的数量：%s<=======",recentFiles.size()));

            return recentFiles;
        }
        finally {
            logger.error("fileNames 跟踪信息:{}", sb);
        }
    }

    /**
     * 关闭连接
     *
     * @throws IOException
     */
    public void disconnect() throws IOException {
        if (ftp.isConnected()) {
            try {
                ftp.logout();
            } catch (IOException ex) {
                logger.error("disconnect断开连接发生异常", ex);
            }
            try{
                ftp.disconnect();
            }
            catch (Exception ex){}
            is_connected = false;
        }
    }

    /**
     * 设置工作路径
     *
     * @param dir
     * @return
     */
    private boolean setWorkingDirectory(String dir) {
        if (!is_connected) {
            return false;
        }
        //如果目录不存在创建目录
        try {
            if (createDirecroty(dir)) {
                return ftp.changeWorkingDirectory(dir);
            }
        } catch (IOException e) {
            logger.error("setWorkingDirectory断开连接发生异常", e);
        }
        return false;

    }

    /**
     * 是否连接
     *
     * @return
     */
    public boolean isConnected() {
        return is_connected;
    }

    /**
     * 创建目录
     *
     * @param remote
     * @return
     * @throws IOException
     */
    private boolean createDirecroty(String remote) throws IOException {
        if(StringUtils.isEmpty(remote)){
            return false;
        }
        boolean success = true;
        String directory = remote.substring(0, remote.lastIndexOf("/") + 1);
        // 如果远程目录不存在，则递归创建远程服务器目录
        if (!directory.equalsIgnoreCase("/") && !ftp.changeWorkingDirectory(new String(directory))) {
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            while (true) {
                String subDirectory = new String(remote.substring(start, end));
                if (!ftp.changeWorkingDirectory(subDirectory)) {
                    if (ftp.makeDirectory(subDirectory)) {
                        ftp.changeWorkingDirectory(subDirectory);
                    } else {
                        log.error("mack directory error :/" + subDirectory);
                        return false;
                    }
                }
                start = end + 1;
                end = directory.indexOf("/", start);
                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break;
                }
            }
        }
        return success;
    }
}
