package com.ruoyi.device.websocket;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.ruoyi.device.websocket.model.TsbWebSocketMessage;
import jakarta.websocket.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * 调试宝 websocket 客户端用户集
 * 
 * @author lwm
 */
public class TsbWebSocketUsers
{
    /**
     * TsbWebSocketUsers 日志控制器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(TsbWebSocketUsers.class);

    /**
     * deviceSn -> session用户集
     */
    private static final Map<Long, Session> SESSION_USERS = new ConcurrentHashMap<>();

    /**
     * 注册会话；同一 deviceSn 仅允许一个有效连接
     *
     * @param key 唯一键 设备sn码
     * @param session session用户信息
     * @return true 注册成功；false 该设备已有连接
     */
    public static boolean tryPut(Long key, Session session)
    {
        Session existing = SESSION_USERS.get(key);
        if (existing != null && existing.isOpen() && !existing.getId().equals(session.getId()))
        {
            LOGGER.info("设备编号={} 已有 WebSocket 连接, sessionId={}", key, existing.getId());
            return false;
        }
        put(key, session);
        return true;
    }

    /**
     * 设备是否已有有效 WebSocket 连接（其他用户）
     */
    public static boolean isDeviceConnectedByOtherUser(Long deviceSn, Long userId)
    {
        if (deviceSn == null)
        {
            return false;
        }
        Session session = SESSION_USERS.get(deviceSn);
        if (session == null)
        {
            return false;
        }
        if (!session.isOpen())
        {
            SESSION_USERS.remove(deviceSn, session);
            return false;
        }
        Long userIdFromSession = getUserIdFromSession(session);
        if (userIdFromSession == null || userIdFromSession.equals(userId))
        {
            return false;
        }
        return true;
    }

    /**
     * 设备是否已有有效 WebSocket 连接（当前用户）
     */
    public static boolean isDeviceConnectedByCurrentUser(Long deviceSn, Long userId)
    {
        if (deviceSn == null)
        {
            return false;
        }
        Session session = SESSION_USERS.get(deviceSn);
        if (session == null)
        {
            return false;
        }
        if (!session.isOpen())
        {
            SESSION_USERS.remove(deviceSn, session);
            return false;
        }
        Long userIdFromSession = getUserIdFromSession(session);
        if (userIdFromSession == null || !userIdFromSession.equals(userId))
        {
            return false;
        }
        return true;
    }

    /**
     * 获取用户Id
     */
    private static Long getUserIdFromSession(Session session)
    {
        if (session == null)
        {
            return null;
        }
        Object userIdObj = session.getUserProperties().get(TsbWebSocketConstants.USER_ID_KEY);
        if (userIdObj instanceof Long)
        {
            return (Long) userIdObj;
        }
        if (userIdObj instanceof Number)
        {
            return ((Number) userIdObj).longValue();
        }
        return null;
    }

    /**
     * 注册会话；同一 deviceSn 仅保留最新连接
     *
     * @param key 唯一键 设备sn码
     * @param session session用户信息
     */
    public static void put(Long key, Session session)
    {
        Session oldSession = SESSION_USERS.put(key, session);
        // 假如旧会话存在，且不是当前会话（此时相当于被新连接替换了，还是同一个设备，所以不需要释放锁）
        if (oldSession != null && oldSession.isOpen() && !oldSession.getId().equals(session.getId()))
        {
            LOGGER.info("设备编号={}, 旧会话={}, 被新会话={}替换", key, oldSession.getId(), session.getId());
        }
        LOGGER.info("WebSocket注册会话, deviceSn={}, sessionId={}", key, session.getId());
    }

    /**
     * 移出 session用户信息
     *
     * @param key 键 设备sn码
     */
    public static boolean remove(Long key)
    {
        LOGGER.info("正在移出session用户信息, deviceSn={}", key);
        Session remove = SESSION_USERS.remove(key);
        if (remove != null)
        {
            boolean containsValue = SESSION_USERS.containsValue(remove);
            LOGGER.info("SESSION_USERS移出结果 - {}", containsValue ? "失败" : "成功");
            return containsValue;
        }
        else
        {
            return true;
        }
    }

    /**
     * 获取在线 session用户集
     *
     * @return 返回用户集合
     */
    public static Map<Long, Session> getSessionUsers()
    {
        return SESSION_USERS;
    }

    /**
     * 已有session会话 按照文本消息发送 msg统一格式消息
     *
     * @param session session会话
     * @param msg 消息内容
     */
    public static void sendMessageToUserByText(Session session, TsbWebSocketMessage msg)
    {
        if (session != null && session.isOpen())
        {
            try
            {
                session.getBasicRemote().sendText(JSON.toJSONString(msg, JSONWriter.Feature.WriteNulls));
            }
            catch (IOException e)
            {
                LOGGER.error("session={}, [发送消息异常]", session.getId(), e);
            }
        }
        else
        {
            LOGGER.info("session={}, [已离线,无法发送消息]", session != null ? session.getId() : "null");
        }
    }

}
