package net.northking.cctp.scriptcase.api.component.ws;


import cn.hutool.extra.ssh.JschUtil;
import com.alibaba.fastjson.JSON;
import io.micrometer.core.instrument.util.StringUtils;
import net.northking.cctp.scriptcase.constants.ScriptConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@Component
@ServerEndpoint(value = "/pub/file/connect")
public class JSchConnectWS {

    private Session session;

    private com.jcraft.jsch.Session jschSession;

    private final static String SCRIPT_VAR_REGEX = "\\$\\{([^}]*)\\}";

    private final static Pattern SCRIPT_VAR_PATTERN = Pattern.compile(SCRIPT_VAR_REGEX);

    public static boolean containScriptVar(String str){
        return SCRIPT_VAR_PATTERN.matcher(str).find();
    }

    private final static Logger logger = LoggerFactory.getLogger(JSchConnectWS.class);

    @OnOpen
    public void onOpen(Session session) throws IOException {
        this.session = session;
        Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
        List<String> host = requestParameterMap.get(ScriptConstant.WS_HOST);
        if (host == null || host.size() == 0) {
            onClose(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, ScriptConstant.WS_HOST_NULL));
        }
        List<String> port = requestParameterMap.get(ScriptConstant.WS_PORT);
        if (port == null || port.size() == 0) {
            onClose(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, ScriptConstant.WS_PORT_NULL));
        }
        List<String> user = requestParameterMap.get(ScriptConstant.WS_USER);
        if (user == null || user.size() == 0) {
            onClose(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, ScriptConstant.WS_USER_NULL));
        }
        List<String> password = requestParameterMap.get(ScriptConstant.WS_PWD);
        if (password == null || password.size() == 0) {
            onClose(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, ScriptConstant.WS_PWD_NULL));
        }
        if (host != null && port != null && user != null && password != null) {
            try {
                com.jcraft.jsch.Session jschSession = JschUtil.getSession(host.get(0), Integer.parseInt(port.get(0)), user.get(0), password.get(0));
                this.jschSession = jschSession;
                boolean connected = jschSession.isConnected();
                logger.info("连接【" + host.get(0) + "】结果为:" + connected);
                Map<String, Object> map = new HashMap<>();
                map.put(ScriptConstant.TYPE, ScriptConstant.STR_ONE);
                map.put(ScriptConstant.WS_HOST, host.get(0));
                map.put(ScriptConstant.CONNECT, connected);
                session.getBasicRemote().sendText(JSON.toJSONString(map));
            } catch (Exception e) {
                Map<String, Object> map = new HashMap<>();
                map.put(ScriptConstant.TYPE, ScriptConstant.ERROR);
                if (e.getMessage().contains(ScriptConstant.TIMED_OUT)) {
                    map.put(ScriptConstant.MESSAGE,ScriptConstant.CONNECT_TIME_OUT);
                } else if (e.getMessage().contains(ScriptConstant.AUTH)) {
                    map.put(ScriptConstant.MESSAGE,ScriptConstant.CONNECT_PWD_ERR);
                } else {
                    map.put(ScriptConstant.MESSAGE,ScriptConstant.CONNECT_EXCEPTION);
                }
                session.getBasicRemote().sendText(JSON.toJSONString(map));
                logger.error("连接服务器异常", e);
            }
        }
    }


    @OnMessage
    public void onMessage(String cmd) {
        try {
            if (cmd.equals(ScriptConstant.PING)) {
                try {
                    session.getBasicRemote().sendText(ScriptConstant.PONG);
                } catch (IOException e) {
                    logger.error("发送心跳异常", e);
                }
            } else {
                if (containScriptVar(cmd)) {
                    Map<String, Object> resultMap = new HashMap<>();
                    resultMap.put(ScriptConstant.TYPE, ScriptConstant.ERROR);
                    resultMap.put(ScriptConstant.MESSAGE, ScriptConstant.FILE_PATH_ERR);
                    session.getBasicRemote().sendText(JSON.toJSONString(resultMap));
                } else {
                    com.jcraft.jsch.Session jschSession = this.jschSession;
                    String exec = JschUtil.exec(jschSession, cmd, null);
                    List<String> list = new ArrayList<>();
                    String[] split = exec.split("\n");
                    for (String name : split) {
                        if (!StringUtils.isBlank(name)) {
                            char charAt = name.charAt(name.length() - 1);
                            if (String.valueOf(charAt).equals("/")) {
                                list.add(name.substring(0, name.length() - 1));
                            }
                        }
                    }
                    logger.info("执行命令:" + cmd);
                    String[] strings = cmd.split(ScriptConstant.SHOW_FILE_NAME);
                    Map<String, Object> resultMap = new HashMap<>();
                    resultMap.put(ScriptConstant.TYPE, ScriptConstant.STR_TWO);
                    resultMap.put(ScriptConstant.DATA, list);
                    resultMap.put(ScriptConstant.FILE_PATH, strings[strings.length - 1]);
                    session.getBasicRemote().sendText(JSON.toJSONString(resultMap));
                }
            }
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    @OnError
    public void onError(Session session, Throwable e) {
        logger.info("SessionId:{},异常信息:{}", session.getId(), e);
    }


    @OnClose
    public void onClose(CloseReason cr) {
        logger.info("ws通道关闭:{},:{}", this.session.getId(), cr);
        try {
            com.jcraft.jsch.Session jschSession = this.jschSession;
            if (null != jschSession) {
                //断开连接
                JschUtil.close(jschSession);
            }
            if (cr != null && cr.getReasonPhrase() != null && cr.getCloseCode().equals(CloseReason.CloseCodes.NORMAL_CLOSURE)) {
                session.getBasicRemote().sendText(cr.getReasonPhrase());
            }
            this.session.close();
        } catch (IOException e) {
            logger.error("ws断开异常:", e);
        }
    }

}
