package cn.com.poc.expose.websocket;


import cn.com.poc.expose.websocket.constant.WsHandlerMatcher;
import cn.com.poc.expose.websocket.handler.AbstractWsHandler;
import cn.com.poc.expose.websocket.holder.WSHandlerHolder;
import cn.com.yict.framemax.core.config.Config;
import cn.com.yict.framemax.core.exception.BusinessException;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.UUID;

/**
 * @author alex.yao
 * @date 2023/12/7
 **/
@Component
public class SuperLinkWebSocketServer extends WebSocketServer {

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

    private boolean serverStarted = false;

    private final String LOG_KEY = "log_trace_id";

    private SuperLinkWebSocketServer() {
    }

    public SuperLinkWebSocketServer(int port, int decodercount) {
        super(new InetSocketAddress(port), decodercount);
    }

    @Override
    public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
//        auth(webSocket);

        initWebSocketTraceId();

        String path = webSocket.getResourceDescriptor();
        logger.warn("websocket new connection open , address:{} ,path:{} ", webSocket.getRemoteSocketAddress().toString(), path);
        AbstractWsHandler handlerClass = WsHandlerMatcher.getWsHandlerClass(path);
        if (handlerClass != null) {
            WSHandlerHolder.set(handlerClass);
        } else {
            webSocket.send("{\"code\":-1, \"message\":\"path mismatch\"}");
            webSocket.close();
        }
    }

    private void auth(WebSocket webSocket) {
        String hostName = webSocket.getRemoteSocketAddress().getHostName();
        logger.info("connection hostname:{}", hostName);
        String[] split = Config.get("white.list.ip").split(",");
        if (Arrays.stream(split).noneMatch(ip -> ip.equals(hostName))) {
            throw new BusinessException("no authority");
        }
    }


    @Override
    public void onMessage(WebSocket webSocket, String s) {
        logger.info("{} connection send message:{}", webSocket.getRemoteSocketAddress().toString(), s.length() < 1024 ? s : "response too long");
        WSHandlerHolder.get().doHandler(webSocket, s);
    }


    @Override
    public void onClose(WebSocket webSocket, int i, String s, boolean b) {
        logger.warn("connection is close:{}", webSocket.getRemoteSocketAddress().toString() + webSocket.getResourceDescriptor());
        WSHandlerHolder.clear();
    }

    @Override
    public void onError(WebSocket webSocket, Exception e) {
        logger.warn("connection is error:{}", webSocket.getRemoteSocketAddress().toString() + webSocket.getResourceDescriptor());
        WSHandlerHolder.clear();
    }

    @Override
    public void onStart() {
        logger.warn("---------------------------------websocket start--------------------------------------");
    }

    @Override
    public void start() {
        serverStarted = true;
        super.start();
    }

    @Override
    public void stop() throws IOException, InterruptedException {
        serverStarted = false;
        super.stop();
    }

    @Override
    public void stop(int i) throws InterruptedException {
        serverStarted = false;
        super.stop(i);
    }

    public boolean isRun() {
        return this.serverStarted;
    }


    private void initWebSocketTraceId() {
        String traceId = UUID.randomUUID().toString().replaceAll("-", "");
        MDC.put(LOG_KEY, traceId);
    }
}
