package calls.presentation import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import calls.data.remote.WebRtcManager import chats.data.remote.signalr.ChatEvent import chats.data.remote.signalr.ChatHubClient import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import org.webrtc.* import javax.inject.Inject enum class CallStatus { IDLE, INCOMING, OUTGOING, CONNECTED, ENDED } data class CallState( val status: CallStatus = CallStatus.IDLE, val chatId: String? = null, val callerName: String = "", val callerAvatar: String? = null, val isMuted: Boolean = false, val isSpeakerOn: Boolean = false, val localVideoTrack: VideoTrack? = null, val remoteVideoTrack: VideoTrack? = null ) @HiltViewModel class CallViewModel @Inject constructor( private val webRtcManager: WebRtcManager, private val signalrClient: ChatHubClient ) : ViewModel() { private val _state = MutableStateFlow(CallState()) val state: StateFlow = _state.asStateFlow() init { observeSignaling() } private fun observeSignaling() { signalrClient.events .onEach { event -> when (event) { is ChatEvent.CallIncoming -> onIncomingCall(event) is ChatEvent.CallAnswered -> onCallAnswered(event) is ChatEvent.IceCandidateReceived -> onIceCandidate(event) is ChatEvent.CallEnded -> onCallEnded() else -> Unit } } .launchIn(viewModelScope) } private fun onIncomingCall(event: ChatEvent.CallIncoming) { _state.update { it.copy( status = CallStatus.INCOMING, chatId = event.chatId, callerName = "User ${event.from}" // TODO: Load actual user info ) } // Set remote description from offer webRtcManager.setRemoteDescription(event.offer, SessionDescription.Type.OFFER, object : SdpObserver { override fun onCreateSuccess(p0: SessionDescription?) {} override fun onSetSuccess() {} override fun onCreateFailure(p0: String?) {} override fun onSetFailure(p0: String?) {} }) } private fun onCallAnswered(event: ChatEvent.CallAnswered) { _state.update { it.copy(status = CallStatus.CONNECTED) } webRtcManager.setRemoteDescription(event.answer, SessionDescription.Type.ANSWER, object : SdpObserver { override fun onCreateSuccess(p0: SessionDescription?) {} override fun onSetSuccess() {} override fun onCreateFailure(p0: String?) {} override fun onSetFailure(p0: String?) {} }) } private fun onIceCandidate(event: ChatEvent.IceCandidateReceived) { // Parse candidate JSON and add to peer connection // webRtcManager.addIceCandidate(...) } private fun onCallEnded() { _state.update { it.copy(status = CallStatus.ENDED) } webRtcManager.close() } fun acceptCall() { val chatId = _state.value.chatId ?: return // Create answer and send via SignalR } fun endCall() { val chatId = _state.value.chatId ?: return // Send call_end via SignalR onCallEnded() } }