"use strict";
/**
 * useRealtimeCollaboration Hook - Real-time multi-user collaboration
 * Features: WebSocket connections, user presence, cursor tracking, live updates
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAdvancedCollaboration = exports.useRealtimeCollaboration = void 0;
const react_1 = require("react");
const uuid_1 = require("uuid");
// Default WebSocket URL (in production, this would come from environment)
const DEFAULT_WEBSOCKET_URL = 'ws://localhost:8080/collaboration';
// Generate random user color
const generateUserColor = () => {
    const colors = [
        '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
        '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9'
    ];
    return colors[Math.floor(Math.random() * colors.length)];
};
const useRealtimeCollaboration = ({ enabled = true, conversationId, userId = (0, uuid_1.v4)(), userName = 'Anonymous User', userAvatar, websocketUrl = DEFAULT_WEBSOCKET_URL, reconnectInterval = 3000, maxReconnectAttempts = 5, heartbeatInterval = 30000, cursorUpdateThrottle = 100, onUserJoined, onUserLeft, onCursorMoved, onEventReceived, onConnectionChange } = {}) => {
    const [isConnected, setIsConnected] = (0, react_1.useState)(false);
    const [connectionStatus, setConnectionStatus] = (0, react_1.useState)('disconnected');
    const [collaborators, setCollaborators] = (0, react_1.useState)([]);
    const [currentUser, setCurrentUser] = (0, react_1.useState)(null);
    const websocketRef = (0, react_1.useRef)(null);
    const reconnectTimeoutRef = (0, react_1.useRef)();
    const heartbeatIntervalRef = (0, react_1.useRef)();
    const cursorThrottleRef = (0, react_1.useRef)();
    const reconnectAttemptsRef = (0, react_1.useRef)(0);
    const messageQueueRef = (0, react_1.useRef)([]);
    // Initialize current user
    (0, react_1.useEffect)(() => {
        if (enabled) {
            const user = {
                id: userId,
                name: userName,
                avatar: userAvatar,
                color: generateUserColor(),
                isActive: true,
                lastSeen: new Date()
            };
            setCurrentUser(user);
        }
    }, [enabled, userId, userName, userAvatar]);
    // Connect to WebSocket
    const connect = (0, react_1.useCallback)(() => {
        if (!enabled || !conversationId)
            return;
        setConnectionStatus('connecting');
        try {
            const url = `${websocketUrl}?conversationId=${conversationId}&userId=${userId}`;
            const ws = new WebSocket(url);
            ws.onopen = () => {
                console.log('🔗 Collaboration WebSocket connected');
                setIsConnected(true);
                setConnectionStatus('connected');
                reconnectAttemptsRef.current = 0;
                onConnectionChange?.(true);
                // Send pending messages
                if (messageQueueRef.current.length > 0) {
                    messageQueueRef.current.forEach(message => {
                        ws.send(JSON.stringify(message));
                    });
                    messageQueueRef.current = [];
                }
                // Send user join event
                const joinEvent = {
                    type: 'user-joined',
                    data: currentUser,
                    conversationId
                };
                ws.send(JSON.stringify(joinEvent));
                // Start heartbeat
                heartbeatIntervalRef.current = setInterval(() => {
                    if (ws.readyState === WebSocket.OPEN) {
                        ws.send(JSON.stringify({ type: 'heartbeat', timestamp: Date.now() }));
                    }
                }, heartbeatInterval);
            };
            ws.onmessage = (event) => {
                try {
                    const message = JSON.parse(event.data);
                    handleWebSocketMessage(message);
                }
                catch (error) {
                    console.error('Failed to parse WebSocket message:', error);
                }
            };
            ws.onclose = (event) => {
                console.log('🔗 Collaboration WebSocket disconnected:', event.code, event.reason);
                setIsConnected(false);
                setConnectionStatus('disconnected');
                onConnectionChange?.(false);
                // Clear heartbeat
                if (heartbeatIntervalRef.current) {
                    clearInterval(heartbeatIntervalRef.current);
                }
                // Attempt reconnection
                if (enabled && reconnectAttemptsRef.current < maxReconnectAttempts) {
                    reconnectAttemptsRef.current++;
                    console.log(`🔄 Attempting reconnection ${reconnectAttemptsRef.current}/${maxReconnectAttempts}`);
                    reconnectTimeoutRef.current = setTimeout(() => {
                        connect();
                    }, reconnectInterval * reconnectAttemptsRef.current);
                }
            };
            ws.onerror = (error) => {
                console.error('🔗 Collaboration WebSocket error:', error);
                setConnectionStatus('error');
            };
            websocketRef.current = ws;
        }
        catch (error) {
            console.error('Failed to create WebSocket connection:', error);
            setConnectionStatus('error');
        }
    }, [enabled, conversationId, userId, websocketUrl, currentUser, onConnectionChange, heartbeatInterval, reconnectInterval, maxReconnectAttempts]);
    // Handle WebSocket messages
    const handleWebSocketMessage = (0, react_1.useCallback)((message) => {
        const event = {
            id: message.id || (0, uuid_1.v4)(),
            type: message.type,
            userId: message.userId,
            timestamp: new Date(message.timestamp),
            data: message.data,
            conversationId: message.conversationId
        };
        switch (event.type) {
            case 'user-joined':
                const newUser = event.data;
                setCollaborators(prev => {
                    const existing = prev.find(u => u.id === newUser.id);
                    if (existing) {
                        return prev.map(u => u.id === newUser.id ? { ...u, ...newUser, isActive: true } : u);
                    }
                    return [...prev, newUser];
                });
                onUserJoined?.(newUser);
                break;
            case 'user-left':
                setCollaborators(prev => prev.filter(u => u.id !== event.userId));
                onUserLeft?.(event.userId);
                break;
            case 'cursor-moved':
                const cursorData = event.data;
                setCollaborators(prev => prev.map(u => u.id === event.userId
                    ? { ...u, cursor: cursorData, lastSeen: new Date() }
                    : u));
                onCursorMoved?.(event.userId, cursorData);
                break;
            case 'text-changed':
            case 'message-sent':
            case 'reaction-added':
            case 'custom':
                // Update user activity
                setCollaborators(prev => prev.map(u => u.id === event.userId
                    ? { ...u, lastSeen: new Date() }
                    : u));
                break;
        }
        onEventReceived?.(event);
    }, [onUserJoined, onUserLeft, onCursorMoved, onEventReceived]);
    // Connect when enabled and conversation ID is available
    (0, react_1.useEffect)(() => {
        if (enabled && conversationId) {
            connect();
        }
        return () => {
            disconnect();
        };
    }, [enabled, conversationId, connect]);
    // Disconnect WebSocket
    const disconnect = (0, react_1.useCallback)(() => {
        if (websocketRef.current) {
            websocketRef.current.close(1000, 'User disconnected');
            websocketRef.current = null;
        }
        if (reconnectTimeoutRef.current) {
            clearTimeout(reconnectTimeoutRef.current);
        }
        if (heartbeatIntervalRef.current) {
            clearInterval(heartbeatIntervalRef.current);
        }
        setIsConnected(false);
        setConnectionStatus('disconnected');
        setCollaborators([]);
    }, []);
    // Reconnect WebSocket
    const reconnect = (0, react_1.useCallback)(() => {
        disconnect();
        setTimeout(connect, 1000);
    }, [disconnect, connect]);
    // Send WebSocket message
    const sendMessage = (0, react_1.useCallback)((message) => {
        if (websocketRef.current?.readyState === WebSocket.OPEN) {
            websocketRef.current.send(JSON.stringify({
                ...message,
                id: (0, uuid_1.v4)(),
                userId,
                timestamp: Date.now()
            }));
        }
        else {
            // Queue message for when connection is restored
            messageQueueRef.current.push(message);
        }
    }, [userId]);
    // Broadcast custom event
    const broadcastEvent = (0, react_1.useCallback)((event) => {
        sendMessage({
            type: event.type,
            data: event.data,
            conversationId: event.conversationId || conversationId
        });
    }, [sendMessage, conversationId]);
    // Broadcast message
    const broadcastMessage = (0, react_1.useCallback)((message) => {
        broadcastEvent({
            type: 'message-sent',
            data: message
        });
    }, [broadcastEvent]);
    // Update cursor position (throttled)
    const updateCursor = (0, react_1.useCallback)((x, y, element) => {
        if (!enabled || !isConnected)
            return;
        if (cursorThrottleRef.current) {
            clearTimeout(cursorThrottleRef.current);
        }
        cursorThrottleRef.current = setTimeout(() => {
            sendMessage({
                type: 'cursor-moved',
                data: { x, y, element }
            });
        }, cursorUpdateThrottle);
    }, [enabled, isConnected, sendMessage, cursorUpdateThrottle]);
    // Update text selection
    const updateSelection = (0, react_1.useCallback)((start, end, text) => {
        if (!enabled || !isConnected)
            return;
        sendMessage({
            type: 'text-changed',
            data: { selection: { start, end, text } }
        });
    }, [enabled, isConnected, sendMessage]);
    // Add reaction to message
    const addReaction = (0, react_1.useCallback)((messageId, emoji) => {
        broadcastEvent({
            type: 'reaction-added',
            data: { messageId, emoji, action: 'add' }
        });
    }, [broadcastEvent]);
    // Remove reaction from message
    const removeReaction = (0, react_1.useCallback)((messageId, emoji) => {
        broadcastEvent({
            type: 'reaction-added',
            data: { messageId, emoji, action: 'remove' }
        });
    }, [broadcastEvent]);
    // Send typing indicator
    const sendTypingIndicator = (0, react_1.useCallback)((isTyping) => {
        sendMessage({
            type: 'typing-indicator',
            data: { isTyping }
        });
    }, [sendMessage]);
    // Share conversation (generate shareable link)
    const shareConversation = (0, react_1.useCallback)(async (conversationId) => {
        // In a real implementation, this would call an API to generate a shareable link
        const shareUrl = `${window.location.origin}/conversation/${conversationId}`;
        // Copy to clipboard
        if (navigator.clipboard) {
            await navigator.clipboard.writeText(shareUrl);
        }
        return shareUrl;
    }, []);
    // Invite user to collaboration session
    const inviteUser = (0, react_1.useCallback)(async (email) => {
        // In a real implementation, this would call an API to send an invitation
        sendMessage({
            type: 'user-invited',
            data: { email, conversationId }
        });
    }, [sendMessage, conversationId]);
    // Kick user from collaboration session
    const kickUser = (0, react_1.useCallback)(async (userIdToKick) => {
        sendMessage({
            type: 'user-kicked',
            data: { userId: userIdToKick }
        });
    }, [sendMessage]);
    // Mute user temporarily
    const muteUser = (0, react_1.useCallback)(async (userIdToMute, duration = 300000) => {
        sendMessage({
            type: 'user-muted',
            data: { userId: userIdToMute, duration }
        });
    }, [sendMessage]);
    // Generate user cursors for display
    const userCursors = collaborators
        .filter(user => user.cursor && user.isActive && user.id !== userId)
        .map(user => ({
        userId: user.id,
        userName: user.name,
        x: user.cursor.x,
        y: user.cursor.y,
        color: user.color
    }));
    // Cleanup on unmount
    (0, react_1.useEffect)(() => {
        return () => {
            disconnect();
        };
    }, [disconnect]);
    return {
        isConnected,
        collaborators,
        currentUser,
        userCursors,
        connectionStatus,
        shareConversation,
        broadcastEvent,
        broadcastMessage,
        updateCursor,
        updateSelection,
        addReaction,
        removeReaction,
        sendTypingIndicator,
        inviteUser,
        kickUser,
        muteUser,
        disconnect,
        reconnect
    };
};
exports.useRealtimeCollaboration = useRealtimeCollaboration;
// Advanced collaboration hook with additional features
const useAdvancedCollaboration = (options) => {
    const baseHook = (0, exports.useRealtimeCollaboration)(options);
    const [voiceChatActive, setVoiceChatActive] = (0, react_1.useState)(false);
    const [videoChatActive, setVideoChatActive] = (0, react_1.useState)(false);
    const [screenShareActive, setScreenShareActive] = (0, react_1.useState)(false);
    const [sharedFiles, setSharedFiles] = (0, react_1.useState)([]);
    // Voice chat functionality
    const startVoiceChat = (0, react_1.useCallback)(async () => {
        if (!options.enableVoiceChat)
            return;
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            setVoiceChatActive(true);
            baseHook.broadcastEvent({
                type: 'voice-chat-started',
                data: { userId: baseHook.currentUser?.id }
            });
            // In a real implementation, set up WebRTC peer connections
            console.log('🎤 Voice chat started');
        }
        catch (error) {
            console.error('Failed to start voice chat:', error);
        }
    }, [options.enableVoiceChat, baseHook]);
    // Video chat functionality
    const startVideoChat = (0, react_1.useCallback)(async () => {
        if (!options.enableVideoChat)
            return;
        try {
            const stream = await navigator.mediaDevices.getUserMedia({
                audio: true,
                video: true
            });
            setVideoChatActive(true);
            baseHook.broadcastEvent({
                type: 'video-chat-started',
                data: { userId: baseHook.currentUser?.id }
            });
            console.log('📹 Video chat started');
        }
        catch (error) {
            console.error('Failed to start video chat:', error);
        }
    }, [options.enableVideoChat, baseHook]);
    // Screen sharing functionality
    const startScreenShare = (0, react_1.useCallback)(async () => {
        if (!options.enableScreenShare)
            return;
        try {
            const stream = await navigator.mediaDevices.getDisplayMedia({
                video: true,
                audio: true
            });
            setScreenShareActive(true);
            baseHook.broadcastEvent({
                type: 'screen-share-started',
                data: { userId: baseHook.currentUser?.id }
            });
            console.log('🖥️ Screen share started');
        }
        catch (error) {
            console.error('Failed to start screen share:', error);
        }
    }, [options.enableScreenShare, baseHook]);
    // File sharing functionality
    const shareFile = (0, react_1.useCallback)(async (file) => {
        if (!options.enableFileSharing)
            return;
        setSharedFiles(prev => [...prev, file]);
        baseHook.broadcastEvent({
            type: 'file-shared',
            data: {
                fileName: file.name,
                fileSize: file.size,
                fileType: file.type,
                userId: baseHook.currentUser?.id
            }
        });
        console.log('📎 File shared:', file.name);
    }, [options.enableFileSharing, baseHook]);
    return {
        ...baseHook,
        voiceChatActive,
        videoChatActive,
        screenShareActive,
        sharedFiles,
        startVoiceChat,
        startVideoChat,
        startScreenShare,
        shareFile,
        stopVoiceChat: () => setVoiceChatActive(false),
        stopVideoChat: () => setVideoChatActive(false),
        stopScreenShare: () => setScreenShareActive(false)
    };
};
exports.useAdvancedCollaboration = useAdvancedCollaboration;
exports.default = exports.useRealtimeCollaboration;
//# sourceMappingURL=useRealtimeCollaboration.js.map