package com.ssyf.task.websocket;

import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * 分布式 WS 协调器
 * 负责全局判断某个直播间是否需要建立连接，以及防止重复连接
 */
@Slf4j
@Service
public class GlobalWsCoordinator {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 当前微服务节点的唯一标识，重启后变化
    private final String CURRENT_NODE_ID = IdUtil.fastSimpleUUID();

    private static final String LOCK_WS_CREATE = "lock:ws:create:";
    private static final String KEY_WS_STATE = "ws:room:state:";
    // 状态缓存时间，略大于心跳上报间隔，节点宕机后Key会自动过期，其他节点即可接管
    private static final long STATE_TTL_SECONDS = 60;

    @PostConstruct
    public void init() {
        log.info("WebSocket Coordinator initialized. Node ID: {}", CURRENT_NODE_ID);
    }

    /**
     * 检查是否需要由当前节点建立连接
     * @param roomId 直播间ID
     * @return true-当前节点应该建立连接（或已经持有连接）；false-其他节点已建立
     */
    public boolean shouldConnect(Integer roomId) {
        String roomKey = KEY_WS_STATE + roomId;

        // 1. 快速检查：Redis中是否已有活跃状态
        RoomWsState state = (RoomWsState) redisTemplate.opsForValue().get(roomKey);
        if (state != null) {
            if (CURRENT_NODE_ID.equals(state.getHolderNodeId())) {
                return true;
            }
            // 别人持有的，且Key没过期，说明别人活得好好的
            log.debug("Room {} WS connection held by node {}", roomId, state.getHolderNodeId());
            return false;
        }

        // 2. 慢速路径：状态不存在（没连过 或 上个节点挂了），尝试竞争分布式锁
        String lockKey = LOCK_WS_CREATE + roomId;
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，等待2秒，持有10秒（足够建立连接）
            if (lock.tryLock(2, 10, TimeUnit.SECONDS)) {
                // Double Check
                state = (RoomWsState) redisTemplate.opsForValue().get(roomKey);
                if (state != null) {
                    return false;
                }
                
                log.info("Acquired lock for room {}, checking out permission to connect.", roomId);
                return true;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        
        return false;
    }

    /**
     * 注册/刷新连接状态 (Heartbeat)
     * 连接建立成功后，必须定期调用此方法续期 Redis Key
     */
    public void refreshState(Integer roomId, String anchorName) {
        String roomKey = KEY_WS_STATE + roomId;
        RoomWsState state = new RoomWsState();
        state.setRoomId(String.valueOf(roomId));
        state.setHolderNodeId(CURRENT_NODE_ID);
        state.setLastHeartbeatTime(System.currentTimeMillis());
        state.setAnchorName(anchorName);
        
        // 如果是首次，记录连接时间（这里简化处理，实际可以通过参数传递）
        // 每次刷新重置过期时间
        redisTemplate.opsForValue().set(roomKey, state, STATE_TTL_SECONDS, TimeUnit.SECONDS);
    }

    /**
     * 释放连接状态 (当本地断开连接或服务关闭时调用)
     */
    public void releaseState(Integer roomId) {
        String roomKey = KEY_WS_STATE + roomId;
        RoomWsState state = (RoomWsState) redisTemplate.opsForValue().get(roomKey);
        // 只有自己持有的才删，防止误删别人的
        if (state != null && CURRENT_NODE_ID.equals(state.getHolderNodeId())) {
            redisTemplate.delete(roomKey);
            log.info("Released WS state for room {}", roomId);
        }
    }
    
    public String getCurrentNodeId() {
        return CURRENT_NODE_ID;
    }
}