package com.jihe.punchnet.sdlan.network

import com.google.protobuf.Message
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetSocketAddress
import java.net.SocketAddress
import java.nio.ByteBuffer
import java.nio.ByteOrder

enum class StartStopFlag {
    IsStart,
    IsStop,
}

// 本地启动或者停止服务的信息
class StartStopChanInfo(
    val flag: StartStopFlag,
    val packetID: Int?,
)

enum class PacketType(val id: UByte) {
    Empty(0x00u),
    RegisterSuper(0x01u),
    RegisterSuperACK(0x02u),
    RegisterSuperNAK(0x04u),

    UnRegisterSuper(0x05u),

    QueryInfo(0x06u),
    PeerInfo(0x07u),

    Ping(0x08u),
    Pong(0x09u),

    Event(0x10u),

    Command(0x11u),
    CommandACK(0x12u),

    FlowTracer(0x15u),

    Register(0x20u),
    RegisterACK(0x21u),

    StunRequest(0x30u),
    StunReply(0x31u),

    StunProbe(0x32u),
    StunProbeReply(0x33u),

    Data(0xffu);

    companion object {
        private val innermap = PacketType.entries.map {it.id to it}.toMap()

        fun fromValue(value: UByte): PacketType? {
            return innermap[value]
        }
    }
}

fun PacketType.toUByte(): UByte {
    return this.id
}


// tcp发送过来的通道里面的信息
class SDLanTCP(
    val packetID: UInt,
    val packetType: PacketType,
    val currentPacket: ByteArray,
)

enum class ConnectingState {
    NotConnected,
    Connecting,
    Connected,
}

suspend fun sendToSock(node: Node, content: ByteArray, sock: SDLanSock) {
    val target: SocketAddress
    when (sock.family) {
        IPFamily.IPV4 -> {
            target = InetSocketAddress(Inet4Address.getByAddress(sock.ip), sock.port)
        }
        IPFamily.IPV6 -> {
            target = InetSocketAddress(Inet6Address.getByAddress(sock.ip), sock.port)
        }
    }
    node.udpSockV4.send_to(content, target)
}

suspend fun sendToSock(node: Node, content: List<Byte>, sock: SDLanSock) {
    sendToSock(node, content.toByteArray(), sock)
}

fun encodeToUDPMessage(msg: Message?, packetType: PacketType): List<Byte> {
    val result: MutableList<Byte> = mutableListOf()
    val msgByte = msg?.toByteArray()?.toList()?:listOf<Byte>()
    result.add(packetType.toUByte().toByte())
    result.addAll(msgByte)
    return result
}

fun encodeToTcpMessage(msg: Message?, packetID: Int, packetType: PacketType): List<Byte> {
    val msgByte = msg?.toByteArray()?.toList()?:listOf<Byte>()
    val result: MutableList<Byte> = mutableListOf()

    result.addAll(ByteBuffer.allocate(2)
        .order(ByteOrder.BIG_ENDIAN)
        .putShort((msgByte.size + 5).toShort())
        .array().toList())

    result.addAll(ByteBuffer.allocate(4)
        .order(ByteOrder.BIG_ENDIAN)
        .putInt(packetID)
        .array().toList())

    result.add(packetType.toUByte().toByte())
    result.addAll(msgByte)

    return result
}

enum class StunProbeAttr {
    None,
    Port,
    Peer,
}