package moe.lava.neon.api.gateway

import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.decodeFromJsonElement
import moe.lava.neon.api.ApiConstants.json

internal fun <T : Event.Outgoing> T.pack(): Payload.Outgoing<T> {
    val opcode: Int = when (this) {
        is Event.Heartbeat -> 1
        is Event.Identify -> 2
        is Event.Resume -> 6
        is Event.QoSHeartbeat -> 40
    }
    return Payload.Outgoing(op = opcode, d = this)
}

internal fun Payload.Unknown.asIncoming() : Payload.WithSequence {
    return when (op) {
        0 -> when (t) {
            "READY" -> decode<Event.Ready>()
            "RESUMED" -> decode<Event.Resumed>()
            else -> this
        }
        1 -> decode<Event.Heartbeat>()
        7 -> decodeObject(Event.Reconnect)
        9 -> decode<Event.InvalidSession>()
        10 -> decode<Event.Hello>()
        11 -> decodeObject(Event.HeartbeatAck)
        else -> this
    }
}

private inline fun <reified T : Event.Incoming> Payload.Unknown.decode(): Payload.Incoming<T> =
    Payload.Incoming(
        op = op,
        d = json.decodeFromJsonElement<T>(d ?: JsonNull),
        s = s,
        t = t,
    )

private inline fun <reified T : Event.Incoming> Payload.Unknown.decodeObject(obj: T): Payload.Incoming<T> =
    Payload.Incoming(
        op = op,
        d = obj,
        s = s,
        t = t,
    )
