package com.njcn.gather.detection.util.socket.communication.model;

import cn.hutool.core.util.StrUtil;
import com.njcn.gather.detection.util.socket.communication.handler.ConnectionLifecycleHandler;
import com.njcn.gather.detection.util.socket.communication.handler.HeartbeatMessageStrategy;
import com.njcn.gather.detection.util.socket.communication.handler.SocketMessageHandler;

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

/**
 * Generic communication connection context.
 * Stage 4-A keeps transport identity and optional callbacks in one place so
 * Netty client/server code does not need to know detection business types.
 *
 * @author hongawen
 * @date 2026/04/07
 */
public class ConnectionContext {

    public static final String ATTR_PRE_DETECTION_PARAM = "preDetectionParam";

    public static final String ATTR_CONTRAST_PARAM = "contrastDetectionParam";

    public static final String ATTR_SOCKET_MESSAGE_HANDLER = "socketMessageHandler";

    public static final String ATTR_CONNECTION_LIFECYCLE_HANDLER = "connectionLifecycleHandler";

    public static final String ATTR_HEARTBEAT_MESSAGE_STRATEGY = "heartbeatMessageStrategy";

    private final String userId;

    private final ConnectionType connectionType;

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

    public ConnectionContext(String userId, ConnectionType connectionType) {
        this.userId = userId;
        this.connectionType = connectionType;
    }

    public static ConnectionContext of(String userId, ConnectionType connectionType) {
        return new ConnectionContext(userId, connectionType);
    }

    public String getUserId() {
        return userId;
    }

    public ConnectionType getConnectionType() {
        return connectionType;
    }

    /**
     * Key refactor point: the transport foundation now resolves the session
     * key from one place instead of reassembling it across multiple classes.
     */
    public String getSessionKey() {
        if (StrUtil.isBlank(userId) || connectionType == null) {
            return userId;
        }
        return userId + connectionType.getSessionTag();
    }

    public ConnectionContext addAttribute(String key, Object value) {
        if (StrUtil.isNotBlank(key) && value != null) {
            attributes.put(key, value);
        }
        return this;
    }

    public ConnectionContext addMessageHandler(SocketMessageHandler handler) {
        return addAttribute(ATTR_SOCKET_MESSAGE_HANDLER, handler);
    }

    public SocketMessageHandler getMessageHandler() {
        return getAttribute(ATTR_SOCKET_MESSAGE_HANDLER, SocketMessageHandler.class);
    }

    public ConnectionContext addLifecycleHandler(ConnectionLifecycleHandler lifecycleHandler) {
        return addAttribute(ATTR_CONNECTION_LIFECYCLE_HANDLER, lifecycleHandler);
    }

    public ConnectionLifecycleHandler getLifecycleHandler() {
        return getAttribute(ATTR_CONNECTION_LIFECYCLE_HANDLER, ConnectionLifecycleHandler.class);
    }

    public ConnectionContext addHeartbeatStrategy(HeartbeatMessageStrategy heartbeatMessageStrategy) {
        return addAttribute(ATTR_HEARTBEAT_MESSAGE_STRATEGY, heartbeatMessageStrategy);
    }

    public HeartbeatMessageStrategy getHeartbeatStrategy() {
        return getAttribute(ATTR_HEARTBEAT_MESSAGE_STRATEGY, HeartbeatMessageStrategy.class);
    }

    public Object getAttribute(String key) {
        return attributes.get(key);
    }

    public <T> T getAttribute(String key, Class<T> type) {
        Object value = attributes.get(key);
        if (type.isInstance(value)) {
            return type.cast(value);
        }
        return null;
    }

    public Map<String, Object> getAttributes() {
        return attributes;
    }
}
