package com.ktg.framework.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;


/**
 * 支持同一个code多端接收消息
 */
@Component
@ServerEndpoint("/websocket/android/{code}")
@Slf4j
public class WebSocketAndroid {
    private Session session;
    private String code;
    // 静态变量，记录当前在线连接数（线程安全）
    private static int onlineCount = 0;
    // 存放所有客户端连接（线程安全）
    private static CopyOnWriteArraySet<WebSocketAndroid> webSocketSet = new CopyOnWriteArraySet<>();
    // 核心修改：code与连接集合的映射（一个code对应多个连接）
    private static ConcurrentHashMap<String, Set<WebSocketAndroid>> webSocketMap2 = new ConcurrentHashMap<>();

    // 存储所有会话（备用）
    private final static List<Session> SESSIONS = Collections.synchronizedList(new ArrayList<>());
    private Thread heartbeatThread;

    /**
     * 建立连接
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("code") String code) {
        this.session = session;
        this.code = code;
        webSocketSet.add(this);
        SESSIONS.add(session);

        // 关键：将当前连接加入code对应的集合（不存在则创建）
        webSocketMap2.computeIfAbsent(code, k -> ConcurrentHashMap.newKeySet())
                .add(this);

        addOnlineCount(); // 在线数+1

        // 启动心跳线程
        heartbeatThread = new Thread(() -> {
            try {
                sendHeartbeats(session, code);
            } catch (IOException e) {
                log.error("心跳线程异常", e);
            }
        });
        heartbeatThread.start();

        log.info("[连接ID:{}] 建立连接, 当前总连接数:{}", this.code, getOnlineCount());
        log.info("心跳线程序号{}, 当前存活线程数{}", heartbeatThread.getId(), Thread.activeCount());
    }

    /**
     * 发送心跳包
     */
    private void sendHeartbeats(Session session, String code) throws IOException {
        int heartbeatInterval = 60000; // 60秒间隔
        while (!Thread.currentThread().isInterrupted()) { // 检查线程中断状态
            try {
                Thread.sleep(heartbeatInterval);
                if (session.isOpen()) {
                    session.getBasicRemote().sendText("heartbeat");
                } else {
                    break; // 连接已关闭，退出循环
                }
            } catch (InterruptedException e) {
                // 线程被中断，退出循环
                Thread.currentThread().interrupt();
                break;
            } catch (IOException e) {
                log.error("[连接ID:{}] 心跳发送失败", code, e);
                break;
            }
        }
    }

    /**
     * 断开连接
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        SESSIONS.remove(this.session);

        // 从code对应的集合中移除当前连接
        Set<WebSocketAndroid> connections = webSocketMap2.get(code);
        if (connections != null) {
            connections.remove(this);
            // 若集合为空，从map中删除该code
            if (connections.isEmpty()) {
                webSocketMap2.remove(code);
            }
        }

        subOnlineCount(); // 在线数-1

        // 关闭心跳线程
        if (heartbeatThread != null && heartbeatThread.isAlive()) {
            log.info("关闭[连接ID:{}]的心跳线程序号{}, 当前存活线程数{}",
                    code, heartbeatThread.getId(), Thread.activeCount());
            heartbeatThread.interrupt(); // 中断线程
            try {
                heartbeatThread.join(1000); // 等待1秒，确保线程退出
            } catch (InterruptedException e) {
                log.error("[连接ID:{}] 心跳线程关闭异常", code, e);
                Thread.currentThread().interrupt();
            }
        }

        log.info("[连接ID:{}] 断开连接, 当前总连接数:{}", code, getOnlineCount());
    }

    /**
     * 发送错误
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("[连接ID:{}] 发生错误", this.code, error);
    }

    /**
     * 收到消息
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("[连接ID:{}] 收到消息:{}", this.code, message);
    }

    /**
     * 给指定code的所有连接发送消息
     */
    public static void sendMessage(String code, String message) {
        Set<WebSocketAndroid> connections = webSocketMap2.get(code);
        if (connections == null || connections.isEmpty()) {
            log.warn("【websocket】code:{} 无在线连接，无法发送消息", code);
            return;
        }

        // 遍历所有连接发送消息
        for (WebSocketAndroid webSocket : connections) {
            try {
                if (webSocket.session.isOpen()) {
                    webSocket.session.getBasicRemote().sendText(message);
                    log.info("【websocket】给code:{}的连接发送消息成功:{}", code, message);
                } else {
                    log.warn("【websocket】code:{}的连接已关闭，跳过发送", code);
                }
            } catch (Exception e) {
                log.error("【websocket】给code:{}的连接发送消息失败", code, e);
            }
        }
    }

    /**
     * 群发消息（所有连接）
     */
    public static void sendMassMessage(String message) {
        try {
            for (Session session : SESSIONS) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(message);
                    log.info("【websocket】群发消息:{} 到会话:{}", message, session.getId());
                }
            }
        } catch (Exception e) {
            log.error("【websocket】群发消息失败", e);
        }
    }

    /**
     * 在线人数统计
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketAndroid.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketAndroid.onlineCount--;
    }
}
