package com.nbport.zgwl.seal.handler;

import com.alibaba.fastjson2.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

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

/**
 * 签章平台WebSocket处理器
 *
 * 职责：
 * 1. 管理WebSocket连接
 * 2. 接收签章平台回调后，实时推送给对应的前端页面
 * 3. 提供轮询兜底机制
 *
 * @author xiaofengzhou
 */
@Component
public class SealWebSocketHandler extends TextWebSocketHandler {

    private static final Logger log = LoggerFactory.getLogger(SealWebSocketHandler.class);

    private static final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<String, String> requestSessionMap = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<String, Map<String, Object>> callbackCache = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionId = session.getId();
        sessions.put(sessionId, session);
        log.info("WebSocket连接建立: sessionId={}", sessionId);
        sendMessage(session, "{\"type\":\"connected\",\"sessionId\":\"" + sessionId + "\"}");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        log.debug("收到WebSocket消息: sessionId={}, payload={}", session.getId(), payload);

        try {
            Map<String, Object> msgMap = JSON.parseObject(payload, Map.class);
            String action = (String) msgMap.get("action");

            if ("subscribe".equals(action)) {
                String requestId = (String) msgMap.get("requestId");
                if (requestId != null) {
                    requestSessionMap.put(requestId, session.getId());
                    log.info("WebSocket订阅: requestId={}, sessionId={}", requestId, session.getId());

                    Map<String, Object> cached = callbackCache.get(requestId);
                    if (cached != null) {
                        sendCallbackToSession(session, requestId, (String) cached.get("callbackType"), cached);
                        callbackCache.remove(requestId);
                    }
                }
            } else if ("unsubscribe".equals(action)) {
                String requestId = (String) msgMap.get("requestId");
                if (requestId != null) {
                    requestSessionMap.remove(requestId);
                    log.info("WebSocket取消订阅: requestId={}", requestId);
                }
            } else if ("ping".equals(action)) {
                sendMessage(session, "{\"type\":\"pong\"}");
            }
        } catch (Exception e) {
            log.error("处理WebSocket消息失败", e);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String sessionId = session.getId();
        sessions.remove(sessionId);
        requestSessionMap.entrySet().removeIf(entry -> sessionId.equals(entry.getValue()));
        log.info("WebSocket连接关闭: sessionId={}, status={}", sessionId, status);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("WebSocket传输错误: sessionId={}", session.getId(), exception);
        sessions.remove(session.getId());
    }

    public void sendCallbackMessage(String requestId, String callbackType, Map<String, Object> data) {
        if (requestId == null) {
            return;
        }

        Map<String, Object> cacheEntry = new ConcurrentHashMap<>();
        cacheEntry.put("callbackType", callbackType);
        cacheEntry.putAll(data);
        callbackCache.put(requestId, cacheEntry);

        String sessionId = requestSessionMap.get(requestId);
        if (sessionId != null) {
            WebSocketSession session = sessions.get(sessionId);
            if (session != null && session.isOpen()) {
                sendCallbackToSession(session, requestId, callbackType, data);
                log.info("WebSocket推送回调成功: requestId={}, callbackType={}", requestId, callbackType);
            } else {
                log.warn("WebSocket session不存在或已关闭: sessionId={}, requestId={}", sessionId, requestId);
                requestSessionMap.remove(requestId);
            }
        } else {
            log.info("没有前端订阅此requestId的回调: requestId={}, 数据已缓存供轮询使用", requestId);
        }
    }

    private void sendCallbackToSession(WebSocketSession session, String requestId, String callbackType, Map<String, Object> data) {
        try {
            Map<String, Object> message = new ConcurrentHashMap<>();
            message.put("type", "callback");
            message.put("requestId", requestId);
            message.put("callbackType", callbackType);
            message.put("data", data);
            sendMessage(session, JSON.toJSONString(message));
        } catch (Exception e) {
            log.error("WebSocket推送失败: sessionId={}", session.getId(), e);
        }
    }

    private void sendMessage(WebSocketSession session, String message) {
        try {
            if (session.isOpen()) {
                synchronized (session) {
                    session.sendMessage(new TextMessage(message));
                }
            }
        } catch (IOException e) {
            log.error("WebSocket发送消息失败", e);
        }
    }

    public Map<String, Object> getCallbackData(String requestId) {
        return callbackCache.remove(requestId);
    }

    public int getOnlineCount() {
        return sessions.size();
    }
}
