package com.hand.hsbc;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

/**
 * <p>
 * Sftp工具类
 * </p>
 *
 * @author huqingniu
 * @version 1.0.0
 * @date 2018/12/24
 */
public class SftpTool {

    public static final Logger logger = LoggerFactory.getLogger(SftpTool.class);

    private String host;

    private String username;

    private int port;

    public SftpTool(String host, String username, int port) {
        this.host = host;
        this.username = username;
        this.port = port;
    }

    /**
     * 登陆sftp
     *
     * @param authTypeMode 认证方式
     * @return 登陆信息
     */
    public Map<String, Object> loginIn(AuthTypeMode authTypeMode) {
        // 解决JSch日志打印问题
        /* JSch.setLogger(new SettleJschLogPrint()); */
        System.setProperty("java.net.preferIPv4Stack", "true");
        try {
            ChannelSftp sftp = null;
            Session session = null;

            JSch jsch = new JSch();
            /* logger.info("获取SFTP服务器连接username:{},host:{},port:{}",username,host,port); */
            session = jsch.getSession(username, host, port);
            logger.info("连接成功建立");
            System.out.println("连接成功建立" + "333333");
            System.out.println("连接成功建立" + username);
            System.out.println("连接成功建立" + host);
            System.out.println("连接成功建立" + port);
            if (AuthTypeEnum.RSA.getCode().equals(authTypeMode.getAuthType())) {
                jsch.addIdentity(authTypeMode.getAuthValue(), "");
            } else {
                session.setPassword(authTypeMode.getAuthValue());
            }
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshConfig.put("PreferredAuthentications", "publickey,gssapi-with-mic,keyboard-interactive,password");
            session.setConfig(sshConfig);
            session.connect();
            logger.info("用户" + username + "成功登陆");
            System.out.println("成功登陆" + "333333");
            Channel channel = session.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;

            HashMap<String, Object> loginInfo = new HashMap<>();
            loginInfo.put("sftp", sftp);
            loginInfo.put("session", session);
            return loginInfo;
        } catch (JSchException e) {
            throw new RuntimeException("user login SFTP server occur exception:" + e);
        }
    }

    /**
     * 退出登陆
     *
     * @param sftp    sftp对象
     * @param session session对象
     */
    public void loginOut(ChannelSftp sftp, Session session) {
        try {
            if (null != sftp && sftp.isConnected()) {
                sftp.disconnect();
            }
            if (null != session && session.isConnected()) {
                session.disconnect();
            }
        } catch (Exception e) {
            logger.warn("用户退出SFTP服务器出现异常:" + e);
        }
    }

    /**
     * 下载文件
     *
     * @param downloadFilePath 要下载的文件所在绝对路径
     * @param downloadFileName 要下载的文件名(sftp服务器上的文件名)
     * @param saveFile         文件存放位置(文件所在绝对路径)
     * @param authTypeMode     用户认证方式
     */
    /*public String download(String downloadFilePath, String downloadFileName, String saveFile, AuthTypeMode authTypeMode)
            throws Exception {
        Assert.notNull(downloadFilePath, "download file absolute path is not null");
        Assert.notNull(downloadFileName, "download file is not null");
        Assert.notNull(saveFile, "save file location is not null");
        Assert.notNull(authTypeMode, "auth type way is not null");

        OutputStream outputStream = null;
        ChannelSftp sftp = null;
        Session session = null;
        try {
            Map<String, Object> loginInfo = loginIn(authTypeMode);
            sftp = (ChannelSftp) loginInfo.get("sftp");
            session = (Session) loginInfo.get("session");

            logger.info("待下载文件地址为:" + downloadFilePath + ",文件名为:" + downloadFileName + ",认证方式:"
                    + authTypeMode.getAuthValue());

            sftp.cd(downloadFilePath);
            *//* sftp.ls(downloadFilePath); *//*
            Vector vector = sftp.ls(downloadFilePath);

            Iterator iterator = vector.iterator();
            String returnFileName ="";
            String conn="";
            while (iterator.hasNext()) {
                ChannelSftp.LsEntry file = (ChannelSftp.LsEntry) iterator.next();
                // 文件名称
                String fileName = file.getFilename();
                if (fileName.indexOf(".XML") != -1) {
                    if (returnFileName!="") {
                        conn=";";
                    }
                    outputStream = new FileOutputStream(saveFile + "\\" + fileName);

                    System.out.println(fileName + "fileName");
                    sftp.get(fileName, outputStream);
                    returnFileName=returnFileName+conn+fileName;

                }



            }
            System.out.println("下载成功" + "333333");
            return returnFileName;

            *//*
             * outputStream = new FileOutputStream(saveFile); sftp.get(downloadFileName,
             * outputStream);
             *//*

            *//* logger.info("文件下载完成!"); *//*


        } finally {
            if (null != outputStream) {
                outputStream.close();
            }
            loginOut(sftp, session);
        }
    }*/

    /**
     * 下载文件
     *  CAMT52V2   日中对账单按照付款账号下载
     *  CAMT53V2   日间对账单按照付款账号下载
     *  ACK1PSRV3  ACK1文件按照02下载
     *  ACK2PSRV3  ACK2文件按照02下载
     *  ACKMT999   ACK3 ACK4只有建机系统下载
     * @param downloadFilePath 要下载的文件所在绝对路径
     * @param systemflag       区分汽车系统和建机系统,01:汽车系统;02:建机系统
     * @param accountnumber    付款账号
     * @param saveFile         文件存放位置(文件所在绝对路径)
     * @param authTypeMode     用户认证方式
     */
    public String downloaddiff(String downloadFilePath, String systemflag, String accountnumber, String saveFile, AuthTypeMode authTypeMode)
            throws Exception {
        Assert.notNull(downloadFilePath, "download file absolute path is not null");
        Assert.notNull(saveFile, "save file location is not null");
        Assert.notNull(authTypeMode, "auth type way is not null");

        OutputStream outputStream = null;
        ChannelSftp sftp = null;
        Session session = null;
        try {
            Map<String, Object> loginInfo = loginIn(authTypeMode);
            sftp = (ChannelSftp) loginInfo.get("sftp");
            session = (Session) loginInfo.get("session");

            sftp.cd(downloadFilePath);
            /* sftp.ls(downloadFilePath); */
            Vector vector = sftp.ls(downloadFilePath);

            Iterator iterator = vector.iterator();
            String returnFileName ="";
            String conn="";
            String downflag = "N";
            while (iterator.hasNext()) {
                ChannelSftp.LsEntry file = (ChannelSftp.LsEntry) iterator.next();
                // 文件名称
                String fileName = file.getFilename();
                if (fileName.indexOf(".XML") != -1) {
                    if (fileName.indexOf("ACK1PSRV3") != -1 || fileName.indexOf("ACK2PSRV3") != -1) {
                        String reqsn = fileName.substring(fileName.indexOf(".", fileName.indexOf(".")+1) + 1,fileName.indexOf(".", fileName.indexOf(".", fileName.indexOf(".")+1)+1));
                        if (reqsn.substring(reqsn.length()-2).equals(systemflag)){
                            downflag = "Y";
                        }
                    }else if(fileName.indexOf("CAMT52V2") != -1 || fileName.indexOf("CAMT53V2") != -1){
                        String accountno = fileName.substring(fileName.indexOf(".", fileName.indexOf(".")+1) + 1,fileName.indexOf(".", fileName.indexOf(".", fileName.indexOf(".")+1)+1));
                        if (accountno.equals(accountnumber)){
                            downflag = "Y";
                        }
                    }else{
                        downflag = "Y";
                    }

                    if (downflag.equals("Y")){
                        if (returnFileName!="") {
                            conn=";";
                        }
                        outputStream = new FileOutputStream(saveFile + "\\" + fileName);

                        System.out.println(fileName + "fileName");
                        sftp.get(fileName, outputStream);
                        returnFileName=returnFileName+conn+fileName;
                    }
                    downflag = "N";

                }



            }
            System.out.println("下载成功" + "333333");
            return returnFileName;

            /*
             * outputStream = new FileOutputStream(saveFile); sftp.get(downloadFileName,
             * outputStream);
             */

            /* logger.info("文件下载完成!"); */


        } finally {
            if (null != outputStream) {
                outputStream.close();
            }
            loginOut(sftp, session);
        }
    }

    /**
     * 上传文件
     *
     * @param uploadPath   上传SFTP完整路径
     * @param uploadFile   上传文件(完整路径)
     * @param authTypeMode 认证方式
     */
    public String upload(String uploadPath, String uploadFile, AuthTypeMode authTypeMode) throws Exception {
        Assert.notNull(uploadPath, "upload path is not null");
        Assert.notNull(uploadFile, "upload file is not null");
        Assert.notNull(authTypeMode, "auth type way is not null");

        InputStream inputStream = null;
        ChannelSftp sftp = null;
        Session session = null;
        try {
            Map<String, Object> loginInfo = loginIn(authTypeMode);
            sftp = (ChannelSftp) loginInfo.get("sftp");
            session = (Session) loginInfo.get("session");

            logger.info("待上传文件为:" + uploadFile + ",上传SFTP服务器路径:" + uploadPath + ",认证方式:" + authTypeMode.getAuthValue());
            File file = new File(uploadFile);
            inputStream = new FileInputStream(file);
            try {
                sftp.cd(uploadPath);
            } catch (SftpException e) {
                return e.getMessage();
                /*
                 * logger.error("SFTP器服务存放文件路径不存在");
                 *
                 * throw new RuntimeException("upload path is not exist");
                 */
            }
            sftp.put(inputStream, file.getName());
            System.out.println("上传文件成功" + "333333");
            logger.info("上传文件成功!");
            return "UPLOAD_SUCCESS";
        } finally {
            if (null != inputStream) {
                inputStream.close();
            }
            loginOut(sftp, session);
        }

    }

    /**
     * authType = PASSWORD,authValue = password authType = rsa,authValue = rsa文件路径
     */
    /*
     * class AuthTypeMode{ private String authType;
     *
     * private String authValue;
     *
     * AuthTypeMode(String authType, String authValue){ this.authType = authType;
     * this.authValue = authValue; }
     *
     * String getAuthType(){ return authType; }
     *
     * String getAuthValue(){ return authValue; } }
     */

    /**
     * 在slf4j日志框架里打印JSch日志
     */
    /*
     * class SettleJschLogPrint implements com.jcraft.jsch.Logger {
     *
     * @Override public boolean isEnabled(int i) { return true; }
     *
     * @Override public void log(int i, String s) { logger.info(s); } }
     */

    enum AuthTypeEnum {

        PASSWORD("PASSWORD", "密码认证"),

        RSA("RSA", "rsa密钥认证");

        private String code;

        private String desc;

        AuthTypeEnum(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public String getCode() {
            return this.code;
        }
    }

    public static void main(String[] args) throws Exception {
        // test

        SftpTool sftpTool = new SftpTool("ecom-sftp.fgcn-pprd.hsbc.com","PC000018926_19960", 10022);

        //sftpTool.upload("\\", "C:\\Users\\User\\Desktop\\testfiledir\\upload\\20201231113053992298.xml", new AuthTypeMode(AuthTypeEnum.RSA.getCode(),"C:\\Users\\User\\Desktop\\hsbstestnew"));

        //sftpTool.download("\\", "", "C:\\Users\\User\\Desktop\\testfiledir\\down_confirm\\", new AuthTypeMode(AuthTypeEnum.RSA.getCode(),"C:\\Users\\User\\Desktop\\hsbstestnew"));








    }
}