package com.changhu.support.ws.manager;

import com.alibaba.fastjson2.JSON;
import com.changhu.support.ws.pojo.dto.WsMsgDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;

import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * author: luozhun
 * desc: 用户连接websocket管理
 * createTime: 2023/11/27 10:57
 */
@Slf4j
public class UserConnectWebsocketManager {

    /**
     * 保存用户链接的map
     * ConcurrentWebSocketSessionDecorator:
     * 这是 Spring WebSocket 提供的一个装饰器类，用于增强底层的 WebSocketSession 的线程安全性。
     * 它通过并发安全的方式包装原始的 WebSocketSession 对象，确保在多线程环境下安全地访问和修改会
     * 话属性，以及进行消息发送操作。
     */
    private static final Map<Long, ConcurrentWebSocketSessionDecorator> SESSION_POLL = new ConcurrentHashMap<>();

    /**
     * 当前在线session数量
     */
    public static Integer getSessionPollSize() {
        return SESSION_POLL.size();
    }

    /**
     * 添加session
     *
     * @param key              key
     * @param webSocketSession webSocketSession
     */
    public static void add(Long key, WebSocketSession webSocketSession) {
        SESSION_POLL.put(key, new ConcurrentWebSocketSessionDecorator(webSocketSession, 10 * 1000, 1024 * 1024));
    }

    /**
     * 删除session
     *
     * @param key key
     * @return 删除的webSocketSession
     */
    public static WebSocketSession remove(Long key) {
        return SESSION_POLL.remove(key);
    }

    /**
     * 删除并同步关闭链接
     *
     * @param key key
     */
    public static void removeAndClose(Long key) {
        Optional.ofNullable(remove(key)).ifPresent(session -> {
            try {
                session.close();
            } catch (IOException e) {
                log.error("session关闭异常:{}", e.getMessage());
            }
        });
    }

    /**
     * 获取webSocketSession
     *
     * @param key key
     * @return webSocketSession
     */
    public static WebSocketSession get(Long key) {
        return SESSION_POLL.get(key);
    }

    /**
     * 给指定用户推送消息
     *
     * @param userId 用户id
     * @param msgDTO 消息内容
     */
    public static <T> void sendToConnectUser(Long userId, WsMsgDTO<T> msgDTO) {
        Optional.ofNullable(SESSION_POLL.get(userId)).ifPresent(webSocketSession -> {
            try {
                webSocketSession.sendMessage(new TextMessage(JSON.toJSONString(msgDTO)));
            } catch (Exception e) {
                log.error("websocket发送消息给:{} 异常:{}", userId, e.getMessage());
            }
        });
    }

    /**
     * 给所有用户发送消息
     */
    public static <T> void sendAllConnectUser(WsMsgDTO<T> msgDTO) {
        SESSION_POLL.keySet().forEach(userId -> sendToConnectUser(userId, msgDTO));
    }

}
