package audio

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.net.DatagramSocket
import java.util.function.Consumer

@Suppress("unused")
/**
 * UDPReceiver is a class that listens for UDP packets on a specified port.
 * It is designed to run in a separate thread and can be stopped when no longer needed.
 * @param portnumber The port to listen for incoming UDP packets (default is 5002
 */
class UDPReceiver(val portnumber: Int = 5002) {
    private lateinit var socket : DatagramSocket
    private var isRunning = false
    private val dataCallback = mutableMapOf<String, Consumer<ByteArray>>()

    /**
     * Start listening for UDP packets on the specified port.
     * @return true if successful, false otherwise
     */
    fun Start() : Boolean{
        return try {
            socket = DatagramSocket(portnumber)
            isRunning = true
            CoroutineScope(Dispatchers.IO).launch {
                while(isRunning){
                    try {
                        val buffer = ByteArray(2048)
                        val packet = java.net.DatagramPacket(buffer, buffer.size)
                        socket.receive(packet)
                        val data = ByteArray(packet.length)
                        System.arraycopy(packet.data, 0, data, 0, packet.length)
                        dataCallback[packet.address.hostAddress].let {
                            it?.accept(data)
                        }

                    } catch (e: Exception) {
                        if (isRunning) {
                            println("Error receiving UDP packet: ${e.message}")
                        }
                    }
                }
            }
            true
        } catch (e: Exception) {
            false
        }
    }

    /**
     * Register a callback function to be called when data is received from the specified IP address.
     * @param ipaddress The IP address to listen for incoming UDP packets.
     * @param callback A callback function that will be called when data is received from the specified IP address.
     */
    fun RequestDataFrom(ipaddress: String, callback: Consumer<ByteArray>){
        dataCallback[ipaddress] = callback
    }

    /**
     * Unregister the callback function for the specified IP address.
     * @param ipaddress The IP address to stop listening for incoming UDP packets.
     */
    fun StopRequestDataFrom(ipaddress: String){
        dataCallback.remove(ipaddress)
    }

    /**
     * Stop listening for UDP packets and close the socket.
     */
    fun Stop(){
        if (isRunning){
            isRunning = false
            socket.close()
        }
    }
}