package com.rosetta.messenger.network

import kotlinx.coroutines.flow.StateFlow

/**
 * Stable runtime port for layers that are not created by Hilt (object managers/services).
 */
interface ProtocolRuntimePort {
    val state: StateFlow<ProtocolState>
    val debugLogs: StateFlow<List<String>>

    fun addLog(message: String)
    fun send(packet: Packet)
    fun sendPacket(packet: Packet)
    fun waitPacket(packetId: Int, callback: (Packet) -> Unit)
    fun unwaitPacket(packetId: Int, callback: (Packet) -> Unit)

    fun requestIceServers()
    fun waitCallSignal(callback: (PacketSignalPeer) -> Unit): (Packet) -> Unit
    fun unwaitCallSignal(callback: (Packet) -> Unit)
    fun waitWebRtcSignal(callback: (PacketWebRTC) -> Unit): (Packet) -> Unit
    fun unwaitWebRtcSignal(callback: (Packet) -> Unit)
    fun waitIceServers(callback: (PacketIceServers) -> Unit): (Packet) -> Unit
    fun unwaitIceServers(callback: (Packet) -> Unit)

    fun getCachedUserInfo(publicKey: String): SearchUser?
    fun isAuthenticated(): Boolean
    fun restoreAuthFromStoredCredentials(
        preferredPublicKey: String? = null,
        reason: String = "background_restore"
    ): Boolean
    fun reconnectNowIfNeeded(reason: String = "foreground_resume")
    fun sendCallSignal(
        signalType: SignalType,
        src: String = "",
        dst: String = "",
        sharedPublic: String = "",
        callId: String = "",
        joinToken: String = ""
    )
    fun sendWebRtcSignal(signalType: WebRTCSignalType, sdpOrCandidate: String)
    suspend fun resolveUserInfo(publicKey: String, timeoutMs: Long = 3000): SearchUser?
}

object ProtocolRuntimeAccess {
    @Volatile private var runtime: ProtocolRuntimePort? = null

    fun install(runtime: ProtocolRuntimePort) {
        this.runtime = runtime
    }

    fun get(): ProtocolRuntimePort {
        return runtime
            ?: error(
                "ProtocolRuntimeAccess is not installed. Install runtime in RosettaApplication.onCreate() before using singleton managers."
            )
    }

    fun isInstalled(): Boolean = runtime != null
}
