package commandServer

import codes.Somecodes.Companion.ValidString
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.tinylog.Logger
import java.net.ServerSocket
import java.net.Socket
import java.util.function.Consumer

@Suppress("unused")
class TCP_PC_Command_Server {
    lateinit var tcpserver: ServerSocket
    lateinit var job: Job
    private val socketMap = mutableMapOf<String, Socket>()

    /**
     * Start TCP Command Server
     * @param port The port number to listen on (default is 5000)
     * @param cb A callback function that will be called when a valid command is received
     * @return true if successful
     */
    fun StartTcpServer(port: Int = 5000, cb: Consumer<String>): Boolean {
        try {
            val tcp = ServerSocket(port)
            tcpserver = tcp
            job = CoroutineScope(Dispatchers.IO).launch {
                Logger.info { "TCP server started" }
                while (isActive) {
                    if (tcpserver.isClosed) break
                    try {
                        tcpserver.accept().use { socket ->
                            {
                                CoroutineScope(Dispatchers.IO).launch {
                                    if (socket != null) {
                                        val key : String = socket.inetAddress.hostAddress+":"+socket.port
                                        socketMap[key] = socket
                                        Logger.info { "Start communicating with $key" }
                                        socket.getInputStream().use { din ->
                                            {
                                                while (isActive) {
                                                    if (din.available()>0){
                                                        val bb = ByteArray(din.available())
                                                        din.read(bb)
                                                        // B4A format, 4 bytes di depan adalah size
                                                        val str = String(bb)
                                                        if (ValidString(str)) cb.accept(str)
                                                    }
                                                }
                                            }
                                        }
                                        Logger.info { "Finished communicating with $key" }
                                        socketMap.remove(key)
                                    }

                                }
                            }
                        }

                    } catch (ex: Exception) {
                        Logger.error { "Failed accepting TCP Socket, Message : ${ex.message}" }
                    }

                }
                Logger.info { "TCP server stopped" }
            }
            return true
        } catch (e: Exception) {
            Logger.error { "Failed to StartTcpServer, Message : ${e.message}" }
        }
        return false
    }

    /**
     * Stop TCP Command Server
     * @return true if succesful
     */
    fun StopTcpCommand(): Boolean {
        try {
            tcpserver.close()
            runBlocking {
                socketMap.values.forEach {
                    it.close()
                }
                socketMap.clear()
                job.join()
            }
            Logger.info { "StopTcpCommand success" }
            return true
        } catch (e: Exception) {
            Logger.error { "Failed to StopTcpServer, Message : ${e.message}" }
        }
        return false
    }
}