package net.northking.cctp.debuger.websocket;

import net.northking.cctp.debuger.bean.DebugerConst;
import net.northking.cctp.debuger.service.InterfaceScriptDebugService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/pub/interface/debug")
public class WSApiSessionManager implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(WSApiSessionManager.class);

    private static Map<String,String> sessionKeyMap = new ConcurrentHashMap<>();
    private static ApplicationContext context;

    @PostConstruct
    public void init(){
        logger.info("Init web session manager ...");
    }
    /**
     * 与界面建立Websocket会话
     * @param session 会话对象
     */
    @OnOpen
    public void onOpen(Session session){
        session.setMaxTextMessageBufferSize(10 * 1024 * 1024);
        session.setMaxBinaryMessageBufferSize(10 * 1024 * 1024);

        String queryString  = session.getQueryString();
        Map<String,String> queryParams = decodeQueryString(queryString);
        logger.info("收到页面建立连接请求:[queryString:{},localSessionId:{}]",queryString,session.getId());

        String sessionId = queryParams.get(DebugerConst.KEY_SESSIONID);
        if (StringUtils.isBlank(sessionId)){
            closeSession(session, "sessionId不能为空");
            return;
        }
        sessionKeyMap.put(session.getId(),sessionId);
        context.getBean(InterfaceScriptDebugService.class).addDebugSession(sessionId,session);
        logger.info("成功建立会话[sessionId:{}]",sessionId);
    }

    private void closeSession(Session session, String reasonMsg) {
        try {
            session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, reasonMsg));
        } catch (IOException e) {
            logger.warn("Error when close session", e);
        }
    }

    private Map<String,String> decodeQueryString(String queryString){
        Map<String,String> queryParams = new HashMap<>();
        if (StringUtils.isNotBlank(queryString)){
            String[] queryParamStrs = StringUtils.split(queryString,"[&]");
            if (queryParams!=null && queryParamStrs.length>0){
                for (String paramStr: queryParamStrs) {
                    String[] param = StringUtils.split(paramStr,"=");
                    queryParams.put(param[0],param[1]);
                }
            }
        }
        return queryParams;
    }


    /**
     * 关闭调试会话
     * @param session
     */
    @OnClose
    public  void onClose(Session session, CloseReason reason){
        logger.info(reason.getCloseCode().getCode()+reason.getReasonPhrase());
        String sessionId =  sessionKeyMap.remove(session.getId());
        logger.info("收到页面关闭连接请求:[sessionId:{},localSessionId:{}]",sessionId,session.getId());
        context.getBean(InterfaceScriptDebugService.class).removeDebugSession(sessionId,session);
        logger.info("成功关闭调试会话[sessionId:{}]",sessionId);
    }

    /**
     * 接收页面消息
     * @param msg
     * @param session
     */
    @OnMessage
    public  void onMessage(String msg,Session session){
        String sessionId =  sessionKeyMap.get(session.getId());
        logger.info("收到页面消息请求:[msg:{},sessionId:{},localSessionId:{}]",msg,sessionId,session.getId());
        if("ping".equalsIgnoreCase(msg)){
            logger.info("Received a ping msg");
            try{
                session.getBasicRemote().sendText("pong");
            }catch (Exception e){
                logger.warn("Error when response ping msg",e);
            }
            return;
        }
        context.getBean(InterfaceScriptDebugService.class).processWebMsg(msg);
    }
    @OnError
    public  void onError(Session session,Throwable t){
        logger.error(String.format("Session Error->sessionId:%s",session.getId()),t);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
}
