'use client' import { useEffect, useRef, useState, useCallback } from 'react' import { io, Socket } from 'socket.io-client' export interface PresenceUser { userId: string name: string cursor: { x: number; y: number } | null color: string } export interface ActivityEvent { action: string userId: string userName: string details: any } const SOCKET_URL = process.env.NEXT_PUBLIC_SOCKET_URL || 'http://localhost:3005' export function useBrainstormSocket( sessionId: string | null, userId: string | null, userName: string | null, onIdeaMoved?: (data: { ideaId: string; positionX: number; positionY: number }) => void ) { const socketRef = useRef(null) const onIdeaMovedRef = useRef(onIdeaMoved) onIdeaMovedRef.current = onIdeaMoved const [others, setOthers] = useState([]) const [activities, setActivities] = useState([]) const [aiProcessingNodeId, setAiProcessingNodeId] = useState(null) const guestIdRef = useRef(null) if (!guestIdRef.current && !userId) { guestIdRef.current = `guest_${Math.random().toString(36).slice(2, 10)}` } const effectiveUserId = userId || guestIdRef.current! useEffect(() => { if (!sessionId) return const socket = io(SOCKET_URL, { auth: { userId: effectiveUserId, sessionId, name: userName || 'Guest', isGuest: !userId, }, transports: ['websocket'], autoConnect: true, }) socketRef.current = socket socket.on('presence:update', (users: PresenceUser[]) => { setOthers(users.filter(u => u.userId !== effectiveUserId)) }) socket.on('cursor:update', (data: { userId: string; cursor: { x: number; y: number } }) => { setOthers(prev => prev.map(u => u.userId === data.userId ? { ...u, cursor: data.cursor } : u )) }) socket.on('activity:new', (event: ActivityEvent) => { setActivities(prev => [event, ...prev].slice(0, 50)) }) socket.on('idea:added', () => {}) socket.on('idea:dismissed', () => {}) socket.on('idea:moved', (data: { ideaId: string; positionX: number; positionY: number }) => { onIdeaMovedRef.current?.(data) }) socket.on('idea:ai_processing', (data: { ideaId: string }) => { setAiProcessingNodeId(data.ideaId) }) socket.on('idea:ai_completed', (data: { ideaId: string }) => { setAiProcessingNodeId(prev => prev === data.ideaId ? null : prev) }) socket.on('idea:ai_failed', (data: { ideaId: string }) => { setAiProcessingNodeId(prev => prev === data.ideaId ? null : prev) }) return () => { socket.disconnect() socketRef.current = null } }, [sessionId, effectiveUserId, userName]) const moveCursor = useCallback((cursor: { x: number; y: number } | null) => { socketRef.current?.emit('cursor:move', cursor) }, []) const broadcastActivity = useCallback((action: string, details?: any) => { socketRef.current?.emit('activity:new', { action, userId: effectiveUserId, userName: userName || 'Guest', details, }) }, [effectiveUserId, userName]) return { others, activities, moveCursor, broadcastActivity, socketRef, aiProcessingNodeId } }