import { useState, useEffect } from 'react';
import type { ServerStatus } from '../types';
import { centralApiBase } from '../api/central';

function monitorWsURL(): string {
  const base = centralApiBase();
  if (base.startsWith('http://') || base.startsWith('https://')) {
    const u = new URL(base);
    u.protocol = u.protocol === 'https:' ? 'wss:' : 'ws:';
    u.pathname = (u.pathname.replace(/\/$/, '') + '/api/ws/monitor').replace(/\/+/g, '/');
    if (!u.pathname.startsWith('/')) u.pathname = '/' + u.pathname;
    return u.toString();
  }
  const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
  const path = `${base.replace(/\/$/, '')}/api/ws/monitor`.replace(/\/+/g, '/');
  return `${proto}//${window.location.host}${path.startsWith('/') ? path : '/' + path}`;
}

function detachWebSocket(ws: WebSocket) {
  ws.onmessage = null;
  ws.onclose = null;
  ws.onerror = null;
  ws.onopen = null;
}

/** Live metrics from the central WebSocket snapshot (gRPC-backed agents only). */
export const useServerMonitor = () => {
  const [statuses, setStatuses] = useState<Record<string, ServerStatus>>({});

  useEffect(() => {
    let cancelled = false;
    let pendingTimer: ReturnType<typeof setTimeout> | undefined;
    let socket: WebSocket | null = null;
    const url = monitorWsURL();

    const clearPending = () => {
      if (pendingTimer !== undefined) {
        clearTimeout(pendingTimer);
        pendingTimer = undefined;
      }
    };

    const scheduleConnect = (delayMs: number) => {
      clearPending();
      pendingTimer = window.setTimeout(() => {
        pendingTimer = undefined;
        if (!cancelled) openSocket();
      }, delayMs);
    };

    const openSocket = () => {
      if (cancelled) return;
      clearPending();
      try {
        socket = new WebSocket(url);
      } catch {
        if (!cancelled) scheduleConnect(2000);
        return;
      }

      const ws = socket;
      ws.onmessage = (ev) => {
        try {
          const msg = JSON.parse(ev.data as string) as {
            type?: string;
            data?: Record<string, ServerStatus>;
          };
          if (msg.type === 'snapshot' && msg.data && typeof msg.data === 'object') {
            setStatuses((prev) => {
              const next = { ...prev };
              for (const [id, st] of Object.entries(msg.data!)) {
                if (st && typeof st === 'object' && 'serverId' in st) {
                  next[id] = st as ServerStatus;
                }
              }
              return next;
            });
          }
        } catch {
          /* ignore bad frame */
        }
      };

      ws.onclose = () => {
        socket = null;
        if (cancelled) return;
        scheduleConnect(2000);
      };
    };

    // 推迟到下个 macrotask，避免 React StrictMode 开发环境下首次 effect 立即卸载时
    // 在 CONNECTING 阶段 close() 触发浏览器 “closed before connection is established” 噪声。
    scheduleConnect(0);

    return () => {
      cancelled = true;
      clearPending();
      if (socket) {
        detachWebSocket(socket);
        socket.close();
        socket = null;
      }
    };
  }, []);

  return statuses;
};
