package com.goldenchart.trading.pipeline;

import com.goldenchart.websocket.UpbitWebSocketClient;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 30초 이상 체결이 없는 구독 종목에 대해 WebSocket 재연결을 요청한다.
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class WebSocketStalenessMonitor {

    private final TradingPipelineProperties props;
    private final TickActivityTracker activityTracker;
    private final UpbitWebSocketClient upbitWebSocketClient;

    private ScheduledExecutorService scheduler;
    private volatile boolean running;
    private volatile long lastCheckAtMs;
    private volatile int lastStaleCount;

    @PostConstruct
    void start() {
        if (!props.isEnabled()) return;
        scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "ws-staleness-monitor");
            t.setDaemon(true);
            return t;
        });
        running = true;
        scheduler.scheduleAtFixedRate(this::check, 15, 15, TimeUnit.SECONDS);
        log.info("[WebSocketStalenessMonitor] 시작 (threshold={}s)", props.getStaleTickSeconds());
    }

    @PreDestroy
    void stop() {
        running = false;
        if (scheduler != null) scheduler.shutdownNow();
    }

    public Map<String, Object> monitorSnapshot() {
        return Map.of(
                "running", running,
                "lastCheckAtMs", lastCheckAtMs,
                "lastStaleCount", lastStaleCount,
                "staleThresholdSec", props.getStaleTickSeconds()
        );
    }

    private void check() {
        lastCheckAtMs = System.currentTimeMillis();
        long now = System.currentTimeMillis();
        long thresholdMs = props.getStaleTickSeconds() * 1000L;
        var subscribed = upbitWebSocketClient.getSubscribedMarkets();
        if (subscribed.isEmpty()) return;

        List<String> stale = new ArrayList<>();
        for (String market : subscribed) {
            long last = activityTracker.lastTickMs(market);
            if (last == 0) {
                // 아직 한 번도 틱 없음 — 구독 직후 30초 유예는 threshold 로 커버
                continue;
            }
            if (now - last > thresholdMs) {
                stale.add(market);
            }
        }
        lastStaleCount = stale.size();
        if (!stale.isEmpty()) {
            log.warn("[WebSocketStalenessMonitor] 틱 정체 {}종목 → WS 재연결 요청: {}",
                    stale.size(), stale);
            upbitWebSocketClient.requestReconnect("stale_ticks:" + stale);
        }
    }
}
