/**
 * Socket Context & Provider
 * Enterprise FinTech Platform — Real-Time Communication System
 *
 * React Context that provides the Socket.IO client instance to the
 * component tree. The provider handles connection lifecycle, JWT
 * authentication, reconnection, heartbeat monitoring, and cleanup.
 */

'use client';

import {
  createContext,
  useContext,
  useEffect,
  useRef,
  useCallback,
  type ReactNode,
} from 'react';
import { io, Socket } from 'socket.io-client';
import { SOCKET_CONFIG, HEARTBEAT_INTERVAL } from '@/config/socket.config';
import { useSocketStore } from '@/store/socket.store';
import { useAuthStore } from '@/store/auth.store';
import { crossTabSync } from '@/lib/cross-tab-sync';

// ===================================================================
// CONTEXT
// ===================================================================

interface SocketContextValue {
  socket: Socket | null;
  isConnected: boolean;
  connect: () => void;
  disconnect: () => void;
}

const SocketContext = createContext<SocketContextValue>({
  socket: null,
  isConnected: false,
  connect: () => {},
  disconnect: () => {},
});

export const useSocket = () => useContext(SocketContext);

// ===================================================================
// HELPERS
// ===================================================================

function redirectToLogin() {
  if (typeof window === 'undefined') return;
  const current = window.location.pathname;
  if (current.startsWith('/auth/')) return;
  window.location.assign('/auth/login');
}

function handleSessionRevoked() {
  crossTabSync.broadcastSessionRevoked();
  useAuthStore.getState().clearAuth();
  redirectToLogin();
}

function handleAccountSuspended() {
  crossTabSync.broadcastAccountSuspended();
  useAuthStore.getState().clearAuth();
  redirectToLogin();
}

// ===================================================================
// PROVIDER
// ===================================================================

interface SocketProviderProps {
  children: ReactNode;
}

export function SocketProvider({ children }: SocketProviderProps) {
  const socketRef = useRef<Socket | null>(null);
  const heartbeatRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const token = useAuthStore((s) => s.token);
  const setConnected = useSocketStore((s) => s.setConnected);
  const setDisconnected = useSocketStore((s) => s.setDisconnected);
  const setLatency = useSocketStore((s) => s.setLatency);
  const setLastPong = useSocketStore((s) => s.setLastPong);
  const setReconnectAttempts = useSocketStore((s) => s.setReconnectAttempts);
  const setError = useSocketStore((s) => s.setError);
  const reset = useSocketStore((s) => s.reset);

  // ===================================================================
  // CONNECT
  // ===================================================================

  const connect = useCallback(() => {
    if (socketRef.current?.connected) return;
    if (!token) {
      setError('No authentication token available');
      return;
    }

    // Close existing socket if any
    socketRef.current?.close();

    const socket = io(`${SOCKET_CONFIG.url}${SOCKET_CONFIG.namespace}`, {
      ...SOCKET_CONFIG.options,
      auth: { token },
    });

    socket.on('connect', () => {
      setConnected(
        (socket as any).data?.userId ?? 'unknown',
        socket.id ?? 'unknown',
      );
    });

    socket.on('disconnect', (reason) => {
      setDisconnected();
      if (reason === 'io server disconnect') {
        setError('Disconnected by server');
      }
    });

    socket.on('connect_error', (err) => {
      setError(err.message);
      setDisconnected();
    });

    socket.on('error', (err: { message: string }) => {
      setError(err.message);
    });

    socket.on('unauthorized', (err: { message: string }) => {
      setError(err.message);
      socket.disconnect();
    });

    socket.on('reconnect_attempt', (attempt) => {
      setReconnectAttempts(attempt);
    });

    socket.on('reconnect', () => {
      setReconnectAttempts(0);
    });

    // Heartbeat: measure latency via ping/pong
    (socket.io as any).on('ping', () => {
      // Client-side latency measurement — Socket.IO handles this internally
    });

    (socket.io as any).on('pong', (latency: number) => {
      setLatency(latency);
      setLastPong(Date.now());
    });

    // Session events from server
    socket.on('session.revoked', () => {
      handleSessionRevoked();
    });

    socket.on('account.suspended', () => {
      handleAccountSuspended();
    });

    socketRef.current = socket;
    socket.connect();
  }, [token, setConnected, setDisconnected, setLatency, setLastPong, setReconnectAttempts, setError]);

  // ===================================================================
  // DISCONNECT
  // ===================================================================

  const disconnect = useCallback(() => {
    if (heartbeatRef.current) {
      clearInterval(heartbeatRef.current);
      heartbeatRef.current = null;
    }
    socketRef.current?.close();
    socketRef.current = null;
    reset();
  }, [reset]);

  // ===================================================================
  // AUTO-CONNECT ON TOKEN CHANGE
  // ===================================================================

  useEffect(() => {
    if (token) {
      connect();
    } else {
      disconnect();
    }

    return () => {
      disconnect();
    };
  }, [token, connect, disconnect]);

  // ===================================================================
  // HEARTBEAT MONITOR
  // ===================================================================

  useEffect(() => {
    if (!socketRef.current?.connected) return;

    heartbeatRef.current = setInterval(() => {
      const socket = socketRef.current;
      if (socket?.connected) {
        // Emit a custom heartbeat event to the server
        socket.emit('heartbeat', { timestamp: Date.now() });
      }
    }, HEARTBEAT_INTERVAL);

    return () => {
      if (heartbeatRef.current) {
        clearInterval(heartbeatRef.current);
        heartbeatRef.current = null;
      }
    };
  }, [token]);

  // ===================================================================
  // CROSS-TAB SYNC
  // ===================================================================

  useEffect(() => {
    const unsub = crossTabSync.onMessage((msg) => {
      if (msg.action === 'LOGOUT' || msg.action === 'SESSION_REVOKED' || msg.action === 'ACCOUNT_SUSPENDED') {
        useAuthStore.getState().clearAuth();
        redirectToLogin();
      }
    });
    return unsub;
  }, []);

  // ===================================================================
  // RENDER
  // ===================================================================

  const value: SocketContextValue = {
    socket: socketRef.current,
    isConnected: socketRef.current?.connected ?? false,
    connect,
    disconnect,
  };

  return (
    <SocketContext.Provider value={value}>
      {children}
    </SocketContext.Provider>
  );
}

