/**
 * WebSocket context for real-time blockchain updates.
 * Provides connection status and event subscription hooks.
 */

import {
  createContext,
  useContext,
  useEffect,
  useState,
  useCallback,
  type ReactNode,
} from 'react';
import {
  wsService,
  type WebSocketStatus,
  type WebSocketEvent,
  type BlockEvent,
  type StatsEvent,
  type TipEvent,
  type MempoolEvent,
} from '../lib/websocket';

interface WebSocketContextValue {
  status: WebSocketStatus;
  isConnected: boolean;
  connect: () => void;
  disconnect: () => void;
  subscribe: <T extends WebSocketEvent>(
    eventType: T['type'],
    callback: (event: T) => void
  ) => () => void;
}

const WebSocketContext = createContext<WebSocketContextValue | null>(null);

interface WebSocketProviderProps {
  children: ReactNode;
  autoConnect?: boolean;
}

export function WebSocketProvider({
  children,
  autoConnect = true,
}: WebSocketProviderProps) {
  const [status, setStatus] = useState<WebSocketStatus>(wsService.getStatus());

  useEffect(() => {
    // Subscribe to status changes
    const unsubscribe = wsService.onStatusChange(setStatus);

    // Auto-connect if enabled
    if (autoConnect) {
      wsService.connect();
    }

    return () => {
      unsubscribe();
    };
  }, [autoConnect]);

  const connect = useCallback(() => {
    wsService.connect();
  }, []);

  const disconnect = useCallback(() => {
    wsService.disconnect();
  }, []);

  const subscribe = useCallback(
    <T extends WebSocketEvent>(
      eventType: T['type'],
      callback: (event: T) => void
    ) => {
      return wsService.subscribe(eventType, callback);
    },
    []
  );

  const value: WebSocketContextValue = {
    status,
    isConnected: status === 'connected',
    connect,
    disconnect,
    subscribe,
  };

  return (
    <WebSocketContext.Provider value={value}>
      {children}
    </WebSocketContext.Provider>
  );
}

export function useWebSocket() {
  const context = useContext(WebSocketContext);
  if (!context) {
    throw new Error('useWebSocket must be used within a WebSocketProvider');
  }
  return context;
}

/**
 * Hook to subscribe to new block events.
 * Returns the latest block and a history of recent blocks.
 */
export function useRealtimeBlocks(maxHistory = 10) {
  const { subscribe, isConnected } = useWebSocket();
  const [latestBlock, setLatestBlock] = useState<BlockEvent | null>(null);
  const [blockHistory, setBlockHistory] = useState<BlockEvent[]>([]);

  useEffect(() => {
    if (!isConnected) return;

    const unsubscribe = subscribe<BlockEvent>('new_block', (event) => {
      setLatestBlock(event);
      setBlockHistory((prev) => [event, ...prev].slice(0, maxHistory));
    });

    return unsubscribe;
  }, [subscribe, isConnected, maxHistory]);

  return { latestBlock, blockHistory, isConnected };
}

/**
 * Hook to subscribe to stats updates.
 * Returns the latest stats with real-time updates.
 */
export function useRealtimeStats() {
  const { subscribe, isConnected } = useWebSocket();
  const [stats, setStats] = useState<StatsEvent | null>(null);

  useEffect(() => {
    if (!isConnected) return;

    const unsubscribe = subscribe<StatsEvent>('stats_update', (event) => {
      setStats(event);
    });

    return unsubscribe;
  }, [subscribe, isConnected]);

  return { stats, isConnected };
}

/**
 * Hook to subscribe to tip updates.
 */
export function useRealtimeTips() {
  const { subscribe, isConnected } = useWebSocket();
  const [tips, setTips] = useState<TipEvent | null>(null);

  useEffect(() => {
    if (!isConnected) return;

    const unsubscribe = subscribe<TipEvent>('tip_update', (event) => {
      setTips(event);
    });

    return unsubscribe;
  }, [subscribe, isConnected]);

  return { tips, isConnected };
}

/**
 * Hook to subscribe to mempool transaction events.
 */
export function useRealtimeMempool(maxHistory = 50) {
  const { subscribe, isConnected } = useWebSocket();
  const [latestTx, setLatestTx] = useState<MempoolEvent | null>(null);
  const [txHistory, setTxHistory] = useState<MempoolEvent[]>([]);

  useEffect(() => {
    if (!isConnected) return;

    const unsubscribe = subscribe<MempoolEvent>('mempool_tx', (event) => {
      setLatestTx(event);
      setTxHistory((prev) => [event, ...prev].slice(0, maxHistory));
    });

    return unsubscribe;
  }, [subscribe, isConnected, maxHistory]);

  return { latestTx, txHistory, isConnected };
}

export default WebSocketContext;
