package cn.iocoder.yudao.module.inspection.websocket;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @Author: chuxia0811
 * @Date: 2023/7/9 10:21
 * @Description :
 */
@ServerEndpoint(value = "/admin-api/websocket/inspectionMsg/{partnerId}")
@Component
public class InspectionMsgSocket {
    private final static Logger log = LoggerFactory.getLogger(InspectionMsgSocket.class);
    // 保存链接的session，key为用户名,value为对应的session名
    private ConcurrentHashMap<Long, Session> sessionMap = new ConcurrentHashMap<>();
    //关键代码，设置一个静态上下文属性appcontext
    private static ApplicationContext appcontext;
    public static void setAppcontext(ApplicationContext appcontext) {
        InspectionMsgSocket.appcontext = appcontext;
    }
    public static ApplicationContext getAppcontext() {
        return appcontext;
    }


    /**
     * 创建连接
     * 用于监听建立连接，当有客户端与该服务端点建立连接时，将会自回调该注解标注的方法
     * @param session
     * @param partnerId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "partnerId") Long partnerId) {
        this.sessionMap.put(partnerId,session);
        log.info("用户{}已创建连接", partnerId);
    }


    /**
     * 用于监听客户端向服务端发送消息，当客户端与服务端发送消息时，将会回调该注解标注的方法
     * {
     *     longitude:124.11,
     *     latitude:125.33,
     *     positionInfo:"山东省济南市市中区八一立交桥"
     * }
     * @param msg
     * @param partnerId
     */
    @OnMessage
    public void onMessage(String msg,@PathParam(value = "partnerId") Long partnerId){
        JSONObject requestMsg = JSONObject.parseObject(msg);
        log.info("用户{}发来消息:{}",partnerId,msg);
    }


    /**
     * 用于监听连接关闭，当客户端与该服务端点断开连接时，将会回调该注解标注的方法
     * @param session
     * @param partnerId
     */
    @OnClose
    public void onClose(Session session,@PathParam(value = "partnerId") Long partnerId){
        this.sessionMap.remove(partnerId);

        log.info("用户{}已关闭连接", partnerId);
    }


    /**
     * 用于监听该连接上的任何错误，当客户端与该服务端点的连接发生任何异常，都将回调该注解标注的方法
     * 注意该方法的参数必选Throwable，可选Sessiion以及0-n个String参数，且String参数需要使用@PathParam注解标注
     * @param throwable
     */
    @OnError
    public void onError(Throwable throwable,@PathParam(value = "partnerId") Long partnerId){
        log.error("用户{}连接发生异常", partnerId);
    }
    /**
     * 群发消息
     *
     * @param message 消息
     */
    public void sendToAll(String message) {
        // 遍历在线map集合
        sessionMap.forEach((onlineSid, toSession) -> {
            // 排除掉自己
            log.info("服务端给客户端群发消息 ==> sid = {}, toSid = {}, message = {}", onlineSid, message);
            toSession.getAsyncRemote().sendText(message);
        });
    }

}
