package com.rosetta.messenger.network

enum class SignalType(val value: Int) {
    CALL(0),
    KEY_EXCHANGE(1),
    ACTIVE_CALL(2),
    END_CALL(3),
    ACTIVE(4),
    END_CALL_BECAUSE_PEER_DISCONNECTED(5),
    END_CALL_BECAUSE_BUSY(6),
    ACCEPT(7),
    RINGING_TIMEOUT(8);

    companion object {
        fun fromValue(value: Int): SignalType =
            entries.firstOrNull { it.value == value }
                ?: throw IllegalArgumentException("Unknown SignalType code: $value")
    }
}

/**
 * Signaling packet (ID: 0x1A / 26).
 * Wire format mirrors desktop packet.signal.peer.ts.
 */
class PacketSignalPeer : Packet() {
    var src: String = ""
    var dst: String = ""
    var sharedPublic: String = ""
    var signalType: SignalType = SignalType.CALL
    var callId: String = ""
    var joinToken: String = ""

    override fun getPacketId(): Int = 0x1A

    override fun receive(stream: Stream) {
        signalType = SignalType.fromValue(stream.readInt8())
        if (
            signalType == SignalType.END_CALL_BECAUSE_BUSY ||
            signalType == SignalType.END_CALL_BECAUSE_PEER_DISCONNECTED ||
            signalType == SignalType.RINGING_TIMEOUT
        ) {
            return
        }
        src = stream.readString()
        dst = stream.readString()
        if (signalType == SignalType.KEY_EXCHANGE) {
            sharedPublic = stream.readString()
        }
        if (
            signalType == SignalType.CALL ||
            signalType == SignalType.ACCEPT ||
            signalType == SignalType.END_CALL
        ) {
            callId = stream.readString()
            joinToken = stream.readString()
        }
    }

    override fun send(): Stream {
        val stream = Stream()
        stream.writeInt16(getPacketId())
        stream.writeInt8(signalType.value)
        if (
            signalType == SignalType.END_CALL_BECAUSE_BUSY ||
            signalType == SignalType.END_CALL_BECAUSE_PEER_DISCONNECTED ||
            signalType == SignalType.RINGING_TIMEOUT
        ) {
            return stream
        }
        stream.writeString(src)
        stream.writeString(dst)
        if (signalType == SignalType.KEY_EXCHANGE) {
            stream.writeString(sharedPublic)
        }
        if (
            signalType == SignalType.CALL ||
            signalType == SignalType.ACCEPT ||
            signalType == SignalType.END_CALL
        ) {
            stream.writeString(callId)
            stream.writeString(joinToken)
        }
        return stream
    }
}
