import { useEffect, useRef, useCallback, useState } from 'react';

/** SSE 事件数据结构 — alert.triggered 事件 */
export interface AlertSSEEvent {
  alert_id: string;
  patient_id: string;
  rule_name: string;
  severity: string;
  detail?: Record<string, unknown>;
  schema_version?: string;
  occurred_at?: string;
}

/** SSE 事件数据结构 — device.readings.synced 事件 */
export interface VitalUpdateSSEEvent {
  patient_id: string;
  count: number;
  device_model?: string;
  date_range?: {
    from?: string;
    to?: string;
  };
  schema_version?: string;
  occurred_at?: string;
}

type ConnectionState = 'connecting' | 'connected' | 'disconnected';

interface UseAlertSSEOptions {
  enabled?: boolean;
  onAlert?: (data: AlertSSEEvent) => void;
  onVitalUpdate?: (data: VitalUpdateSSEEvent) => void;
}

interface UseAlertSSEReturn {
  connected: boolean;
  connectionState: ConnectionState;
  recentAlerts: AlertSSEEvent[];
  reconnect: () => void;
}

const MAX_RECENT_ALERTS = 100;
const INITIAL_DELAY_MS = 1000;
const MAX_DELAY_MS = 30_000;
const MAX_RETRIES = 10;

export function useAlertSSE(options: UseAlertSSEOptions = {}): UseAlertSSEReturn {
  const { enabled = true, onAlert, onVitalUpdate } = options;
  const eventSourceRef = useRef<EventSource | null>(null);
  const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const retryCountRef = useRef(0);
  const reconnectKeyRef = useRef(0);
  const [connected, setConnected] = useState(false);
  const [connectionState, setConnectionState] = useState<ConnectionState>('disconnected');
  const [recentAlerts, setRecentAlerts] = useState<AlertSSEEvent[]>([]);

  const clearReconnectTimer = useCallback(() => {
    if (reconnectTimerRef.current) {
      clearTimeout(reconnectTimerRef.current);
      reconnectTimerRef.current = null;
    }
  }, []);

  const connect = useCallback(() => {
    if (eventSourceRef.current) {
      eventSourceRef.current.close();
      eventSourceRef.current = null;
    }
    clearReconnectTimer();
    setConnected(false);
    setConnectionState('disconnected');

    if (!enabled) return;

    const token = localStorage.getItem('access_token');
    if (!token) return;

    const baseUrl = import.meta.env.VITE_API_BASE_URL || '/api/v1';
    const url = `${baseUrl}/messages/stream?token=${encodeURIComponent(token)}`;
    setConnectionState('connecting');
    const es = new EventSource(url);
    eventSourceRef.current = es;

    es.onopen = () => {
      retryCountRef.current = 0;
      setConnected(true);
      setConnectionState('connected');
    };

    es.addEventListener('alert', (e: MessageEvent) => {
      try {
        const data = JSON.parse(e.data) as AlertSSEEvent;
        onAlert?.(data);
        setRecentAlerts((prev) => {
          const next = [data, ...prev];
          return next.length > MAX_RECENT_ALERTS ? next.slice(0, MAX_RECENT_ALERTS) : next;
        });
      } catch { /* ignore parse errors */ }
    });

    es.addEventListener('vital_update', (e: MessageEvent) => {
      try {
        const data = JSON.parse(e.data) as VitalUpdateSSEEvent;
        onVitalUpdate?.(data);
      } catch { /* ignore parse errors */ }
    });

    es.onerror = () => {
      setConnected(false);
      setConnectionState('disconnected');
      es.close();
      eventSourceRef.current = null;

      retryCountRef.current += 1;
      if (retryCountRef.current > MAX_RETRIES) {
        return;
      }

      const delay = Math.min(
        INITIAL_DELAY_MS * Math.pow(2, retryCountRef.current - 1),
        MAX_DELAY_MS,
      );
      const jitter = delay * (0.5 + Math.random() * 0.5);

      reconnectTimerRef.current = setTimeout(() => {
        reconnectTimerRef.current = null;
        const tokenNow = localStorage.getItem('access_token');
        if (!tokenNow || !enabled) return;
        connect();
      }, jitter);
    };
  }, [enabled, onAlert, onVitalUpdate, clearReconnectTimer]);

  useEffect(() => {
    connect();
    return () => {
      if (eventSourceRef.current) {
        eventSourceRef.current.close();
        eventSourceRef.current = null;
      }
      clearReconnectTimer();
      setConnected(false);
      setConnectionState('disconnected');
    };
  }, [connect, reconnectKeyRef.current]);

  const reconnect = useCallback(() => {
    retryCountRef.current = 0;
    reconnectKeyRef.current += 1;
  }, []);

  return { connected, connectionState, recentAlerts, reconnect };
}
