package gc.mda.signal_batch.monitoring.controller;

import gc.mda.signal_batch.monitoring.service.TrackStreamingMetrics;
import gc.mda.signal_batch.global.websocket.service.ActiveQueryManager;
import gc.mda.signal_batch.global.websocket.service.DailyTrackCacheManager;
import gc.mda.signal_batch.global.websocket.service.StompTrackStreamingService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.view.RedirectView;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@RestController
@RequestMapping("/api/websocket")
@RequiredArgsConstructor
@Tag(name = "WebSocket 모니터링 API", description = "WebSocket 스트리밍 상태 및 쿼리 진행 상황 모니터링 API")
public class WebSocketMonitoringController {

    private final TrackStreamingMetrics trackStreamingMetrics;
    private final StompTrackStreamingService trackStreamingService;
    private final ActiveQueryManager activeQueryManager;
    private final DailyTrackCacheManager dailyTrackCacheManager;

    /**
     * WebSocket 스트리밍 현황 조회
     */
    @GetMapping("/status")
    @Operation(summary = "WebSocket 스트리밍 현황", description = "활성 쿼리 수, 메모리 사용량, 서버 시간 등 WebSocket 스트리밍 전반의 상태를 조회합니다")
    public ResponseEntity<Map<String, Object>> getStreamingStatus() {
        Map<String, Object> status = new HashMap<>();
        
        // 활성 쿼리 수
        status.put("activeQueries", trackStreamingMetrics.getActiveQueryCount());
        
        // 메모리 사용량
        trackStreamingMetrics.recordMemoryUsage();
        Runtime runtime = Runtime.getRuntime();
        Map<String, Long> memory = new HashMap<>();
        memory.put("used", runtime.totalMemory() - runtime.freeMemory());
        memory.put("total", runtime.totalMemory());
        memory.put("max", runtime.maxMemory());
        status.put("memory", memory);
        
        // 서버 시간
        status.put("serverTime", System.currentTimeMillis());
        
        return ResponseEntity.ok(status);
    }

    /**
     * 특정 쿼리의 상태 조회
     */
    @GetMapping("/query/{queryId}/status")
    @Operation(summary = "쿼리 상태 조회", description = "특정 WebSocket 쿼리의 진행 상태, 메시지, 진행률, 스트리밍된 항적 수를 조회합니다")
    public ResponseEntity<Map<String, Object>> getQueryStatus(
            @Parameter(description = "쿼리 ID") @PathVariable String queryId) {
        Map<String, Object> result = new HashMap<>();
        
        var queryStatus = trackStreamingService.getQueryStatus(queryId);
        result.put("status", queryStatus.getStatus());
        result.put("message", queryStatus.getMessage());
        result.put("progress", queryStatus.getProgressPercentage());
        result.put("tracksStreamed", trackStreamingMetrics.getTracksStreamedForQuery(queryId));
        
        return ResponseEntity.ok(result);
    }

    /**
     * 부하 제어 현황 조회
     */
    @GetMapping("/load-control")
    @Operation(summary = "부하 제어 현황", description = "글로벌 동시 쿼리 제한, 대기 큐, 활성 쿼리 상세 정보를 조회합니다")
    public ResponseEntity<Map<String, Object>> getLoadControlStatus() {
        Map<String, Object> status = new HashMap<>();

        // 글로벌 동시 쿼리 제한 상태
        Map<String, Object> concurrency = new HashMap<>();
        concurrency.put("globalActiveQueries", activeQueryManager.getGlobalActiveQueryCount());
        concurrency.put("maxConcurrentGlobal", activeQueryManager.getMaxConcurrentGlobal());
        concurrency.put("waitingInQueue", activeQueryManager.getWaitingCount());
        concurrency.put("registeredQueries", activeQueryManager.getActiveQueryCount());
        status.put("concurrency", concurrency);

        // 활성 쿼리 상세
        status.put("activeQueryDetails", activeQueryManager.getAllActiveQueries().entrySet().stream()
                .map(e -> {
                    Map<String, Object> detail = new HashMap<>();
                    detail.put("sessionId", e.getKey());
                    detail.put("queryId", e.getValue().getQueryId());
                    detail.put("startTime", e.getValue().getStartTime().toString());
                    detail.put("currentTable", String.valueOf(e.getValue().getCurrentTable()));
                    detail.put("processedChunks", e.getValue().getProcessedChunks());
                    detail.put("cancelled", e.getValue().isCancelled());
                    return detail;
                })
                .collect(Collectors.toList()));

        // 메모리 상태
        Runtime runtime = Runtime.getRuntime();
        Map<String, String> memory = new HashMap<>();
        long usedMb = (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024);
        long maxMb = runtime.maxMemory() / (1024 * 1024);
        memory.put("used", usedMb + " MB");
        memory.put("max", maxMb + " MB");
        memory.put("usage", String.format("%.1f%%", (double) usedMb / maxMb * 100));
        status.put("memory", memory);

        return ResponseEntity.ok(status);
    }

    /**
     * 일일 항적 캐시 상태 조회
     */
    @GetMapping("/daily-cache")
    @Operation(summary = "일일 항적 캐시 현황", description = "일일 데이터 인메모리 캐시의 상태, 날짜별 선박 수, 메모리 사용량을 조회합니다")
    public ResponseEntity<Map<String, Object>> getDailyCacheStatus() {
        return ResponseEntity.ok(dailyTrackCacheManager.getCacheStatus());
    }

    /**
     * WebSocket 테스트 페이지로 리다이렉트
     */
    @GetMapping("/test")
    @Operation(summary = "WebSocket 테스트 페이지", description = "WebSocket 스트리밍 테스트 페이지로 리다이렉트합니다")
    public RedirectView redirectToTestPage() {
        return new RedirectView("/websocket/track-streaming-test.html");
    }
}