import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { WebRTCManager, buildUrl, resolveDevWebSocketUrl, } from '@agentuity/frontend';
import { AgentuityContext } from './context';
/**
 * React hook for WebRTC peer-to-peer audio/video/data calls.
 *
 * Supports multi-peer mesh networking, screen sharing, recording, and stats.
 *
 * @example
 * ```tsx
 * function VideoCall({ roomId }: { roomId: string }) {
 *   const {
 *     localVideoRef,
 *     state,
 *     remotePeerIds,
 *     remoteStreams,
 *     hangup,
 *     muteAudio,
 *     isAudioMuted,
 *     startScreenShare,
 *   } = useWebRTCCall({
 *     roomId,
 *     signalUrl: '/call/signal',
 *     callbacks: {
 *       onStateChange: (from, to, reason) => console.log(`${from} → ${to}`, reason),
 *       onRemoteStream: (peerId, stream) => console.log(`Got stream from ${peerId}`),
 *     },
 *   });
 *
 *   return (
 *     <div>
 *       <video ref={localVideoRef} autoPlay muted playsInline />
 *       {remotePeerIds.map((peerId) => (
 *         <RemoteVideo key={peerId} stream={remoteStreams.get(peerId)} />
 *       ))}
 *       <p>State: {state}</p>
 *       <button onClick={() => muteAudio(!isAudioMuted)}>
 *         {isAudioMuted ? 'Unmute' : 'Mute'}
 *       </button>
 *       <button onClick={hangup}>Hang Up</button>
 *     </div>
 *   );
 * }
 * ```
 */
export function useWebRTCCall(options) {
    const context = useContext(AgentuityContext);
    const managerRef = useRef(null);
    const localVideoRef = useRef(null);
    const [state, setState] = useState('idle');
    const [error, setError] = useState(null);
    const [peerId, setPeerId] = useState(null);
    const [remotePeerIds, setRemotePeerIds] = useState([]);
    const [remoteStreams, setRemoteStreams] = useState(new Map());
    const [isAudioMuted, setIsAudioMuted] = useState(false);
    const [isVideoMuted, setIsVideoMuted] = useState(false);
    const [isScreenSharing, setIsScreenSharing] = useState(false);
    const userCallbacksRef = useRef(options.callbacks);
    userCallbacksRef.current = options.callbacks;
    const signalUrl = useMemo(() => {
        if (options.signalUrl.startsWith('ws://') || options.signalUrl.startsWith('wss://')) {
            return options.signalUrl;
        }
        const base = context?.baseUrl ?? window.location.origin;
        const wsBase = base.replace(/^http(s?):/, 'ws$1:');
        return resolveDevWebSocketUrl(buildUrl(wsBase, options.signalUrl));
    }, [context?.baseUrl, options.signalUrl]);
    const managerOptions = useMemo(() => {
        return {
            signalUrl,
            roomId: options.roomId,
            polite: options.polite,
            iceServers: options.iceServers,
            media: options.media,
            dataChannels: options.dataChannels,
            autoReconnect: options.autoReconnect,
            maxReconnectAttempts: options.maxReconnectAttempts,
            connectionTimeout: options.connectionTimeout,
            iceGatheringTimeout: options.iceGatheringTimeout,
            callbacks: {
                onStateChange: (from, to, reason) => {
                    setState(to);
                    if (managerRef.current) {
                        const managerState = managerRef.current.getState();
                        setPeerId(managerState.peerId);
                        setRemotePeerIds(managerState.remotePeerIds);
                        setIsScreenSharing(managerState.isScreenSharing);
                    }
                    userCallbacksRef.current?.onStateChange?.(from, to, reason);
                },
                onConnect: () => {
                    userCallbacksRef.current?.onConnect?.();
                },
                onDisconnect: (reason) => {
                    userCallbacksRef.current?.onDisconnect?.(reason);
                },
                onLocalStream: (stream) => {
                    if (localVideoRef.current) {
                        localVideoRef.current.srcObject = stream;
                    }
                    userCallbacksRef.current?.onLocalStream?.(stream);
                },
                onRemoteStream: (remotePeerId, stream) => {
                    setRemoteStreams((prev) => {
                        const next = new Map(prev);
                        next.set(remotePeerId, stream);
                        return next;
                    });
                    userCallbacksRef.current?.onRemoteStream?.(remotePeerId, stream);
                },
                onTrackAdded: (remotePeerId, track, stream) => {
                    userCallbacksRef.current?.onTrackAdded?.(remotePeerId, track, stream);
                },
                onTrackRemoved: (remotePeerId, track) => {
                    userCallbacksRef.current?.onTrackRemoved?.(remotePeerId, track);
                },
                onPeerJoined: (id) => {
                    setRemotePeerIds((prev) => (prev.includes(id) ? prev : [...prev, id]));
                    userCallbacksRef.current?.onPeerJoined?.(id);
                },
                onPeerLeft: (id) => {
                    setRemotePeerIds((prev) => prev.filter((p) => p !== id));
                    setRemoteStreams((prev) => {
                        const next = new Map(prev);
                        next.delete(id);
                        return next;
                    });
                    userCallbacksRef.current?.onPeerLeft?.(id);
                },
                onNegotiationStart: (remotePeerId) => {
                    userCallbacksRef.current?.onNegotiationStart?.(remotePeerId);
                },
                onNegotiationComplete: (remotePeerId) => {
                    userCallbacksRef.current?.onNegotiationComplete?.(remotePeerId);
                },
                onIceCandidate: (remotePeerId, candidate) => {
                    userCallbacksRef.current?.onIceCandidate?.(remotePeerId, candidate);
                },
                onIceStateChange: (remotePeerId, iceState) => {
                    userCallbacksRef.current?.onIceStateChange?.(remotePeerId, iceState);
                },
                onError: (err, currentState) => {
                    setError(err);
                    userCallbacksRef.current?.onError?.(err, currentState);
                },
                onDataChannelOpen: (remotePeerId, label) => {
                    userCallbacksRef.current?.onDataChannelOpen?.(remotePeerId, label);
                },
                onDataChannelClose: (remotePeerId, label) => {
                    userCallbacksRef.current?.onDataChannelClose?.(remotePeerId, label);
                },
                onDataChannelMessage: (remotePeerId, label, data) => {
                    userCallbacksRef.current?.onDataChannelMessage?.(remotePeerId, label, data);
                },
                onDataChannelError: (remotePeerId, label, err) => {
                    userCallbacksRef.current?.onDataChannelError?.(remotePeerId, label, err);
                },
                onScreenShareStart: () => {
                    setIsScreenSharing(true);
                    userCallbacksRef.current?.onScreenShareStart?.();
                },
                onScreenShareStop: () => {
                    setIsScreenSharing(false);
                    userCallbacksRef.current?.onScreenShareStop?.();
                },
                onReconnecting: (attempt) => {
                    userCallbacksRef.current?.onReconnecting?.(attempt);
                },
                onReconnected: () => {
                    userCallbacksRef.current?.onReconnected?.();
                },
                onReconnectFailed: () => {
                    userCallbacksRef.current?.onReconnectFailed?.();
                },
            },
        };
    }, [
        signalUrl,
        options.roomId,
        options.polite,
        options.iceServers,
        options.media,
        options.dataChannels,
        options.autoReconnect,
        options.maxReconnectAttempts,
        options.connectionTimeout,
        options.iceGatheringTimeout,
    ]);
    useEffect(() => {
        const manager = new WebRTCManager(managerOptions);
        managerRef.current = manager;
        if (options.autoConnect !== false) {
            manager.connect();
        }
        return () => {
            manager.dispose();
            managerRef.current = null;
        };
    }, [managerOptions, options.autoConnect]);
    const connect = useCallback(() => {
        managerRef.current?.connect();
    }, []);
    const hangup = useCallback(() => {
        managerRef.current?.hangup();
        setRemotePeerIds([]);
        setRemoteStreams(new Map());
    }, []);
    const muteAudio = useCallback((muted) => {
        managerRef.current?.muteAudio(muted);
        setIsAudioMuted(muted);
    }, []);
    const muteVideo = useCallback((muted) => {
        managerRef.current?.muteVideo(muted);
        setIsVideoMuted(muted);
    }, []);
    const startScreenShare = useCallback(async (opts) => {
        await managerRef.current?.startScreenShare(opts);
    }, []);
    const stopScreenShare = useCallback(async () => {
        await managerRef.current?.stopScreenShare();
    }, []);
    const createDataChannel = useCallback((config) => {
        return managerRef.current?.createDataChannel(config) ?? new Map();
    }, []);
    const getDataChannelLabels = useCallback(() => {
        return managerRef.current?.getDataChannelLabels() ?? [];
    }, []);
    const getDataChannelState = useCallback((remotePeerId, label) => {
        return managerRef.current?.getDataChannelState(remotePeerId, label) ?? null;
    }, []);
    const sendString = useCallback((label, data) => {
        return managerRef.current?.sendString(label, data) ?? false;
    }, []);
    const sendStringTo = useCallback((remotePeerId, label, data) => {
        return managerRef.current?.sendStringTo(remotePeerId, label, data) ?? false;
    }, []);
    const sendBinary = useCallback((label, data) => {
        return managerRef.current?.sendBinary(label, data) ?? false;
    }, []);
    const sendBinaryTo = useCallback((remotePeerId, label, data) => {
        return managerRef.current?.sendBinaryTo(remotePeerId, label, data) ?? false;
    }, []);
    const sendJSON = useCallback((label, data) => {
        return managerRef.current?.sendJSON(label, data) ?? false;
    }, []);
    const sendJSONTo = useCallback((remotePeerId, label, data) => {
        return managerRef.current?.sendJSONTo(remotePeerId, label, data) ?? false;
    }, []);
    const closeDataChannel = useCallback((label) => {
        return managerRef.current?.closeDataChannel(label) ?? false;
    }, []);
    const getQualitySummary = useCallback(async (remotePeerId) => {
        return managerRef.current?.getQualitySummary(remotePeerId) ?? null;
    }, []);
    const getAllQualitySummaries = useCallback(async () => {
        return managerRef.current?.getAllQualitySummaries() ?? new Map();
    }, []);
    const startRecording = useCallback((streamId, opts) => {
        return managerRef.current?.startRecording(streamId, opts) ?? null;
    }, []);
    const isRecordingFn = useCallback((streamId) => {
        return managerRef.current?.isRecording(streamId) ?? false;
    }, []);
    const stopAllRecordings = useCallback(async () => {
        return managerRef.current?.stopAllRecordings() ?? new Map();
    }, []);
    return {
        localVideoRef,
        state,
        error,
        peerId,
        remotePeerIds,
        remoteStreams,
        isAudioMuted,
        isVideoMuted,
        isDataOnly: options.media === false,
        isScreenSharing,
        connect,
        hangup,
        muteAudio,
        muteVideo,
        startScreenShare,
        stopScreenShare,
        createDataChannel,
        getDataChannelLabels,
        getDataChannelState,
        sendString,
        sendStringTo,
        sendBinary,
        sendBinaryTo,
        sendJSON,
        sendJSONTo,
        closeDataChannel,
        getQualitySummary,
        getAllQualitySummaries,
        startRecording,
        isRecording: isRecordingFn,
        stopAllRecordings,
    };
}
//# sourceMappingURL=webrtc.js.map