package com.ai.da.common.websocket;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;

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


@ServerEndpoint(value = "/notification/{id}")
@Component
@Slf4j
public class NotificationConnection {

    //连接超时
    public static final long MAX_TIME_OUT = 3 * 60 * 1000;

    private Session session;
    private Long userId;
    // 这里用ConcurrentHashMap 因为他是一个线程安全的Map
    private static ConcurrentHashMap<Long, NotificationConnection> websockets = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id) {  // 接收到前端传来的用户ID
        this.session = session;
        this.userId = Long.valueOf(id);
        this.session.setMaxIdleTimeout(MAX_TIME_OUT);
        websockets.put(Long.parseLong(id), this);  //将ID作为key，当前的对象作为Value
        log.info("【建立连接】 用户为：{}", this.session);
        log.info("【建立连接】 用户Id为：{}", id);
        log.info("【当前连接总数】 为：{}", websockets.size());
    }

    @OnClose
    public void onClose(CloseReason reason) {
        log.info("【连接断开】 用户为：{}, sessionId: {}, 原因为{}", this.userId, this.session.getId(), reason);
        log.info("【当前连接总数】 为：{}", websockets.size());
        websockets.remove(this.userId); // 将当前的对象从集合中删除
    }

    /**
     * 错误时调用
     * @param throwable 异常
     */
    @OnError
    public void onError(Throwable throwable) {
        log.info("【连接异常】 用户为：{} ,  sessionId: {}", this.userId, this.session.getId(), throwable);
        websockets.remove(this.userId); // 将当前的对象从集合中删除
        log.info("【当前连接总数】 为：{}", websockets.size());
    }

    //收到了客户端消息执行的操作
    @OnMessage
    public void onMessage(@RequestParam String text){
        Map<String, String> textMap = JSONObject.parseObject(text, Map.class);
        log.info("收到了一条来自 {} 的消息：{}， sessionId：{}", this.userId, textMap.get("text"), this.session.getId());
//        return "已收到你的消息";
        if (textMap.get("text").equals("PING")){
            sendMsg(JSON.toJSONString("PONG"), this.userId);
        }
    }

    public void sendMsg(String message, Long userId)  {
        if (userId == null) {  // 如果等于null则证明是群发
            // 获取当前Map的一个迭代器，遍历Map的方式有很多种，看着来
            // 这个就是遍历这个集合的过程....
            for (Map.Entry<Long, NotificationConnection> entry : websockets.entrySet()) {
                // 获取每一个Entry实例
                // 获取每一个Value，而这个Value就是WebSocket的实例
                NotificationConnection webSocket = entry.getValue();
                // 接下来就是遍历群发
                log.info("广播消息 【给用户】 ：{}发送消息【{}】", webSocket, message);
                try {
                    webSocket.session.getBasicRemote().sendText(message); // 发送！！！！！！！！！
                } catch (IOException e) {
                    log.error("Failed to send message to session {}: {}", webSocket.session.getId(), e.getMessage());
                }
            }
        } else {  // 如果不是群发，则判断ID，其余步骤一致
            // 获取当前Map的一个迭代器，遍历Map的方式有很多种，看着来
            // 这个就是遍历这个集合的过程....
            for (Map.Entry<Long, NotificationConnection> entry : websockets.entrySet()) {
                // 获取每一个Entry实例
                // 获取每一个Value，而这个Value就是WebSocket的实例
                NotificationConnection webSocket = entry.getValue();
                // 获取每一个Key，这个Key就是用户ID
                Long key = entry.getKey();
                // 判断用户ID与当前的Key相等
                if (userId.equals(key)) {
                    log.info("私发消息 【给用户】 ：{}发送消息【{}】", key, message); // 打印
                    if (webSocket.session.isOpen()){
                        // 避免因为网络问题或其他原因导致连接突然关闭而报错
                        try {
                            webSocket.session.getBasicRemote().sendText(message);  // 则发送给当前的用户即可
                        } catch (IOException e) {
                            log.error("Failed to send message to session {}: {}", webSocket.session.getId(), e.getMessage());
                            // 这里可以选择移除关闭的 session
                            websockets.remove(entry.getKey());
                        }
                    }else {
                        log.info("连接已关闭，sessionId:{}, userId:{}", webSocket.session.getId(), key);
                        websockets.remove(entry.getKey());
                    }
                }
            }
        }
    }
}
