// socket.ts
import { router } from '@inertiajs/react';
import { io, type Socket } from 'socket.io-client';
import { SocketEvents, type SocketUser, type ForceLogoutPayload } from '@/types/socket';

// Socket configuration from environment variables
const SOCKET_CONFIG = {
    url: import.meta.env.VITE_SOCKET_URL || 'http://localhost:5000',
    path: import.meta.env.VITE_SOCKET_PATH || '/socket.io',
    reconnectionAttempts: Number(import.meta.env.VITE_SOCKET_RECONNECTION_ATTEMPTS) || 5,
    reconnectionDelay: Number(import.meta.env.VITE_SOCKET_RECONNECTION_DELAY) || 1000,
} as const;

let socket: Socket | null = null;
let isInitializing = false;

/**
 * Initialize Socket.IO connection
 * @param user - User object with id and name
 * @param authToken - Optional authentication token for secure connections
 * @returns Socket instance
 */
export const initSocket = (user: SocketUser, authToken?: string): Socket => {
    // Prevent multiple simultaneous initializations
    if (isInitializing) {
        console.warn('[Socket] Already initializing, please wait...');
        return socket!;
    }

    // Return existing socket if already connected
    if (socket?.connected) {
        return socket;
    }

    isInitializing = true;

    try {
        socket = io(SOCKET_CONFIG.url, {
            path: SOCKET_CONFIG.path,
            query: {
                userId: user.id,
                name: user.name,
                ...(authToken && { token: authToken }),
            },
            reconnection: true,
            reconnectionAttempts: SOCKET_CONFIG.reconnectionAttempts,
            reconnectionDelay: SOCKET_CONFIG.reconnectionDelay,
            reconnectionDelayMax: 5000,
            timeout: 10000,
            autoConnect: true,
            transports: ['websocket', 'polling'],
        });

        // Connection events
        socket.on(SocketEvents.CONNECT, () => {
            console.log('[Socket] ✅ Connected successfully:', socket?.id);
        });

        socket.on(SocketEvents.DISCONNECT, (reason) => {
            console.log('[Socket] ⚠️ Disconnected:', reason);
        });

        socket.on(SocketEvents.CONNECT_ERROR, (error) => {
            console.error('[Socket] ❌ Connection error:', error.message);
        });

        socket.on(SocketEvents.RECONNECT, (attemptNumber) => {
            console.log('[Socket] 🔄 Reconnected after', attemptNumber, 'attempts');
        });

        socket.on(SocketEvents.RECONNECT_ATTEMPT, (attemptNumber) => {
            console.log('[Socket] 🔄 Reconnection attempt:', attemptNumber);
        });

        socket.on(SocketEvents.RECONNECT_ERROR, (error) => {
            console.error('[Socket] ❌ Reconnection error:', error.message);
        });

        socket.on(SocketEvents.RECONNECT_FAILED, () => {
            console.error('[Socket] ❌ Reconnection failed after maximum attempts');
        });

        // Force logout event handler
        socket.on(SocketEvents.FORCE_LOGOUT, (data: ForceLogoutPayload) => {
            console.log('[Socket] ⚡ Force logout event received:', data);
            if (String(data.userId) === String(user.id)) {
                console.warn('[Socket] Logging out user:', user.id);
                disconnectSocket();
                router.post('/logout');
            }
        });

        return socket;
    } catch (error) {
        console.error('[Socket] Failed to initialize:', error);
        throw error;
    } finally {
        isInitializing = false;
    }
};

/**
 * Get the current socket instance
 * @throws Error if socket is not initialized
 * @returns Socket instance
 */
export const getSocket = (): Socket => {
    if (!socket) {
        throw new Error('[Socket] Socket not initialized. Call initSocket() first!');
    }
    return socket;
};

/**
 * Check if socket is connected
 * @returns boolean
 */
export const isSocketConnected = (): boolean => {
    return socket?.connected ?? false;
};

/**
 * Disconnect socket and cleanup
 */
export const disconnectSocket = (): void => {
    if (socket) {
        socket.removeAllListeners();
        socket.disconnect();
        socket = null;
    }
};

/**
 * Emit an event to the socket server
 * @param event - Event name
 * @param data - Data to send
 */
export const emitSocketEvent = <T = any>(event: string, data: T): void => {
    if (!socket?.connected) {
        console.error('[Socket] Cannot emit event - socket not connected');
        return;
    }
    socket.emit(event, data);
};

// Export socket instance for advanced use cases
export { socket };
