package com.inspect.base.core.sftp;

import com.alibaba.fastjson.JSONObject;

import java.io.*;

import com.inspect.base.core.constant.Color;
import com.inspect.base.core.utils.StringUtils;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.net.ftp.FTPSClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SftpClient {
    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    private final SftpLoginConfig sftpLoginConfig;
    private final SftpFactory sftpFactory;

    public SftpClient(SftpLoginConfig sftpLoginConfig, SftpFactory sftpFactory) {
        this.sftpLoginConfig = sftpLoginConfig;
        this.sftpFactory = sftpFactory;
    }

    public String upload(SftpUploadEntity sftpUploadEntity) throws Exception {
//        final String tmp = sftpUploadEntity.getFileFullName();
//        final String fileFullName = tmp.startsWith(sftpLoginConfig.getBasePath()) ? tmp : sftpLoginConfig.getBasePath() + tmp;
        final String tmp = sftpUploadEntity.getFileFullName();
        final String fileFullName = tmp.startsWith(sftpLoginConfig.getBasePath()) ? tmp : sftpLoginConfig.getBasePath() + tmp;

        final String fileFullNameEx = StringUtils.isNotEmpty(sftpLoginConfig.getPrefix())
                ? sftpLoginConfig.getPrefix() + fileFullName
                : fileFullName;

        log.info(Color.GREEN + "[FTP] fileFullName: {}, fileFullNameEx: {}" + Color.END, fileFullName, fileFullNameEx);
        connect((ftps) -> {
            log.info(Color.GREEN + "[FTP] UPLOAD Entity: {}" + Color.END, JSONObject.toJSONString(sftpUploadEntity));
            String path = fileFullNameEx.substring(0, fileFullNameEx.lastIndexOf(StringUtils.SLASH));
            mkdir(ftps, path);
            boolean bOk = ftps.storeFile(fileFullNameEx, sftpUploadEntity.getInputStream());
            log.info(Color.GREEN + "[FTP] UPLOAD {}, PATH: {}, FULL PATH: {}, REPLY CODE: {}, INFO: {}" + Color.END, bOk ? "OK" : "FAIL", path, fileFullNameEx, ftps.getReplyCode(), ftps.getReplyString());
            sftpUploadEntity.getInputStream().close();
        });
        return sftpUploadEntity.toResultPath(sftpLoginConfig.getBasePath());
    }

    public String upload(SftpUploadEntity sftpUploadEntity, SftpClient.Upload upload) throws Exception {
        final String tmp = sftpUploadEntity.getFileFullName();
        final String fileFullName = tmp.startsWith(sftpLoginConfig.getBasePath()) ? tmp : sftpLoginConfig.getBasePath() + tmp;

        final String fileFullNameEx = StringUtils.isNotEmpty(sftpLoginConfig.getPrefix())
                ? sftpLoginConfig.getPrefix() + fileFullName
                : fileFullName;

        log.info("[FTP] fileFullName: {}, fileFullNameEx: {}", fileFullName, fileFullNameEx);
        connect((ftps) -> {
            String path = fileFullNameEx.substring(0, fileFullNameEx.lastIndexOf("/"));
            mkdir(ftps, path);
            log.info("[FTP] UPLOAD fileFullName: {}", fileFullNameEx);
            OutputStream outputStream = ftps.storeFileStream(fileFullNameEx);
            log.info("[FTP] UPLOAD outputStream: {}", outputStream);
            upload.run(outputStream);
            outputStream.close();
            log.info("[FTP] UPLOAD OK: {}", fileFullNameEx);
        });
        return sftpUploadEntity.toResultPath(sftpLoginConfig.getBasePath());
    }

    public void mkdir(FTPSClient ftps, String path) throws IOException {
        ftps.changeWorkingDirectory(StringUtils.SLASH);
        String[] dirs = path.split(StringUtils.SLASH);
        for (String dir : dirs) {
            //log.info("[FTP] dir: {}", dir);
            if (StringUtils.isEmpty(dir)) {
                continue;
            }

            if (!ftps.changeWorkingDirectory(dir)) {
                ftps.makeDirectory(dir);
                ftps.changeWorkingDirectory(dir);
            }
        }
    }

    public void downLoad(String fileFullPath, SftpClient.Download download) throws Exception {
        final String fileFullPathTmp
                = fileFullPath.startsWith(sftpLoginConfig.getBasePath()) ? fileFullPath : sftpLoginConfig.getBasePath() + fileFullPath;

        final String fileFullNameTmpEx = StringUtils.isNotEmpty(sftpLoginConfig.getPrefix()) ? sftpLoginConfig.getPrefix() + fileFullPathTmp : fileFullPathTmp;
        log.info(Color.CYAN + "[FTP] fileFullPath: {}, fileFullNameTmpEx: {}" + Color.END, fileFullPath, fileFullPathTmp);
        connect((ftps) -> {
            InputStream inputStream = ftps.retrieveFileStream(fileFullNameTmpEx);
            if (inputStream == null) {
                log.error("[FTP] DOWNLOAD FAIL, EMPTY STREAM: {}", fileFullPath);
            } else {
                download.run(inputStream);
                inputStream.close();
            }
        });
    }

    private void connect(SftpClient.JoinPoint joinPoint) throws Exception {
        log.debug("[FTP} START <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        long start = System.currentTimeMillis();
        FTPSClient ftps = sftpFactory.connect();
        try {
            ftps.setFileType(FTPSClient.BINARY_FILE_TYPE);
        } catch (IOException e) {
            log.error("[FTP] TIMEOUT, RETRY");
            ftps = sftpFactory.connect();
            ftps.setFileType(FTPSClient.BINARY_FILE_TYPE);
            sftpFactory.init();
        }

        ftps.enterLocalPassiveMode();
        ftps.enterLocalPassiveMode();
        ftps.setFileTransferMode(FTPSClient.STREAM_TRANSFER_MODE);
        ftps.execPROT("P");
        log.debug("[FTP] CONN COST: {}", System.currentTimeMillis() - start);

        start = System.currentTimeMillis();
        joinPoint.run(ftps);
        //log.info("[FTP] TRANSPORT COST: {}", System.currentTimeMillis() - start);
        log.debug("[FTP] END >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        ftps.logout();
    }

    public interface Upload {
        void run(OutputStream outputStream) throws Exception;
    }

    public interface Download {
        void run(InputStream inputStream) throws Exception;
    }

    interface JoinPoint {
        void run(FTPSClient ftpsClient) throws Exception;
    }

    public static void main(String[] args) throws Exception {
//        try {
//            FTPSClient ftps = new FTPSClient(true);
//            ftps.connect("192.168.1.198", 990);
//            boolean loginRes = ftps.login("ftpuser", "atia2018");
//            System.out.println(loginRes);
//            ftps.setFileType(2);
//            //ftps.enterLocalPassiveMode();
//            //ftps.enterLocalPassiveMode();
//            ftps.setControlEncoding("UTF-8");
//            ftps.setFileTransferMode(10);
//            ftps.execPROT("P");
//            ftps.storeFile("11.jpg", new FileInputStream("E:/1.jpg"));
//
//            String fileFullPathTmp = "1/2025/02/26/1339/CCD/1339_20250226095445_2023833_02160558340721910141.jpg";
//            InputStream inputStream = ftps.retrieveFileStream(fileFullPathTmp);
//            if (inputStream == null) {
//                System.out.println("[FTP] DOWNLOAD FAIL, EMPTY STREAM:" + fileFullPathTmp);
//            } else {
//                File tempFile = File.createTempFile("E:\\test001234", ".jpg");
//                tempFile.deleteOnExit();
//                FileOutputStream out = new FileOutputStream(tempFile);
//                IOUtils.copy(inputStream, out);
//                inputStream.close();
//            }
//
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

        try {
            FTPSClient ftps = new FTPSClient(true);
//            ftps.connect("192.168.1.198", 21);
//            boolean loginRes = ftps.login("hangtian", "123qweasd");
//            ftps.connect("124.221.104.159", 10990);
            // ftps.connect("124.221.104.159", 10990);
                      ftps.connect("192.168.1.12", 990);
            boolean loginRes = ftps.login("ftpuser", "atia2018");
            System.out.println(loginRes);
            ftps.setFileType(2);
//            ftps.enterLocalPassiveMode();
            ftps.enterLocalPassiveMode();
            ftps.setControlEncoding("UTF-8");
            ftps.setFileTransferMode(10);
            ftps.execPROT("P");
            ftps.storeFile("1122234567.jpg", new FileInputStream("E:/1.jpg"));


            String fileFullPathTmp = "1122.jpg";
            //String fileFullPathTmp = "/home/hangtian/11.jpg";
            InputStream inputStream = ftps.retrieveFileStream(fileFullPathTmp);
            if (inputStream == null) {
                System.out.println("[FTP] DOWNLOAD FAIL, EMPTY STREAM:" + fileFullPathTmp);
            } else {
                File tempFile = File.createTempFile("test0012345555", ".jpg");
                tempFile.deleteOnExit();
                FileOutputStream out = new FileOutputStream(tempFile);
                IOUtils.copy(inputStream, out);
                inputStream.close();
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
