package com.ruoyi.framework.websocket;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@ServerEndpoint("/websocket/{monitorObj}/{listenObj}/test")
@Component
public class WebSocketServer {

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象
     */
    private static ConcurrentHashMap<String, ConcurrentHashMap<String, WebSocketServer>> webSocketMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 被监听对象
     */
    private String monitorObj = "";
    /**
     * 监听人
     */
    private String listenObj = "";

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("monitorObj") String monitorObj, @PathParam("listenObj") String listenObj) {
        this.session = session;
        this.monitorObj = monitorObj;
        this.listenObj= listenObj;

        if(webSocketMap.containsKey(monitorObj)){
            ConcurrentHashMap<String, WebSocketServer> innerMap = webSocketMap.get(monitorObj);
            if(innerMap.containsKey(listenObj)) {
                innerMap.remove(listenObj);
            }
            innerMap.put(listenObj, this);
        }else{
            ConcurrentHashMap<String, WebSocketServer> innerMap = new ConcurrentHashMap<>();
            innerMap.put(listenObj, this);
            webSocketMap.put(listenObj, innerMap);
        }
        log.info("----------开启监听，监听对象:"+monitorObj+"，监听人:"+listenObj);
        sendMessage("WebSocket连接成功");
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(monitorObj)){
            ConcurrentHashMap<String, WebSocketServer> innerMap = webSocketMap.get(monitorObj);
            if(innerMap.containsKey(listenObj)){
                innerMap.remove(listenObj);
            }
            if(!CollectionUtil.isEmpty(innerMap)) {
                webSocketMap.remove(monitorObj);
            }
        }
        log.info("----------关闭监听，监听对象:"+monitorObj);
    }

    /**
     * 连接错误
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("----------WebSocket连接错误，监听对象:"+this.monitorObj+"，错误原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("----------用户消息，监听对象:"+monitorObj+"，报文:"+message);
        try {
            //解析发送的报文
            if(StringUtils.isNotBlank(message)){
                log.info("----------接收消息为："+message+"，监听对象:"+this.monitorObj+"，监听人:"+this.listenObj);
                sendMessage("WebSocket接收消息成功");
            }
        } catch (Exception e) {
            log.info("----------接收消息为："+message+"，监听对象:"+this.monitorObj+"，监听人:"+this.listenObj+"错误，原因:"+e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 实现服务器主动推送
     * @param message
     */
    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.info("----------服务器主动推送消息："+message+"，失败原因："+e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 发送自定义消息
     * @param message
     * @param monitorObj
     */
    public static void sendInfo(String message, String monitorObj) {
        log.info("-----进入webscoket数据发送，数据为：{}", message);
        if(StringUtils.isNotBlank(monitorObj) && webSocketMap.containsKey(monitorObj)){
            ConcurrentHashMap<String, WebSocketServer> innerMap = webSocketMap.get(monitorObj);
            for(WebSocketServer webServer : innerMap.values()){
                webServer.sendMessage(message);
                log.info("-----成功发送webscoket数据，监听对象："+innerMap.keys()+" 数据为：{}", message);
            }
        }else{
            log.info("------无人监听，监听对象："+monitorObj+" 的长连接！");
        }
    }

}
