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

export type WsStatus = 'connecting' | 'connected' | 'disconnected';

interface WsContextValue {
  status: WsStatus;
  send: (msg: string) => void;
  subscribe: (handler: (msg: string) => void) => () => void;
}

const WsContext = createContext<WsContextValue>({
  status: 'disconnected',
  send: () => {},
  subscribe: () => () => {},
});

export function WsProvider({ children }: { children: React.ReactNode }) {
  const wsRef     = useRef<WebSocket | null>(null);
  const listeners = useRef<Set<(msg: string) => void>>(new Set());
  const [status, setStatus] = useState<WsStatus>('connecting');

  useEffect(() => {
    let cancelled = false;
    let ws: WebSocket | null = null;

    const connect = () => {
      if (cancelled) return;
      ws = new WebSocket(`ws://${window.location.hostname}/ws`);
      wsRef.current = ws;
      setStatus('connecting');
      ws.onopen    = () => { if (!cancelled) setStatus('connected'); };
      ws.onmessage = (e) => { if (!cancelled) listeners.current.forEach(h => h(String(e.data))); };
      ws.onclose   = () => { if (!cancelled) { setStatus('disconnected'); setTimeout(connect, 3000); } };
      ws.onerror   = () => ws?.close();
    };

    connect();
    return () => { cancelled = true; ws?.close(); };
  }, []);

  const send = useCallback((msg: string) => {
    if (wsRef.current?.readyState === WebSocket.OPEN) wsRef.current.send(msg);
  }, []);

  const subscribe = useCallback((handler: (msg: string) => void) => {
    listeners.current.add(handler);
    return () => { listeners.current.delete(handler); };
  }, []);

  return (
    <WsContext.Provider value={{ status, send, subscribe }}>
      {children}
    </WsContext.Provider>
  );
}

export const useWs = () => useContext(WsContext);
