package com.tokilabs.proto_socket

import com.tokilabs.proto_socket.packets.TestData
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.runBlocking
import java.nio.file.Paths
import kotlin.test.Test
import kotlin.test.assertEquals

class TlsTcpTest {
    @Test
    fun testTlsTcpSendReceive() = runBlocking {
        val (serverContext, clientContext) = createTlsContexts()
        val received = CompletableDeferred<TestData>()
        val listenerReady = CompletableDeferred<Unit>()
        val server = TcpServer(
            "127.0.0.1",
            0,
            serverContext,
            { socket -> TcpClient.fromSocket(socket, 0, 0, testParserMap()) },
        )
        server.onClientConnected = { client ->
            addListenerTyped<TestData>(client.communicator) { received.complete(it) }
            listenerReady.complete(Unit)
        }
        server.start()
        val client = dialTcpTls("127.0.0.1", server.port(), clientContext, 0, 0, testParserMap())

        listenerReady.await()
        client.send(TestData.newBuilder().setIndex(43).setMessage("hello tls").build())

        assertEquals(43, received.await().index)
        client.close()
        server.stop()
    }

    @Test
    fun testTlsTcpRequestResponse() = runBlocking {
        val (serverContext, clientContext) = createTlsContexts()
        val server = TcpServer(
            "127.0.0.1",
            0,
            serverContext,
            { socket -> TcpClient.fromSocket(socket, 0, 0, testParserMap()) },
        )
        server.onClientConnected = { client ->
            addRequestListenerTyped<TestData, TestData>(client.communicator) { req ->
                TestData.newBuilder()
                    .setIndex(req.index * 2)
                    .setMessage("tls echo: ${req.message}")
                    .build()
            }
        }
        server.start()
        val client = dialTcpTls("127.0.0.1", server.port(), clientContext, 0, 0, testParserMap())

        val res = sendRequestTyped<TestData, TestData>(
            client.communicator,
            TestData.newBuilder().setIndex(22).setMessage("secure hello").build(),
            timeoutMs = 2_000,
        )

        assertEquals(44, res.index)
        assertEquals("tls echo: secure hello", res.message)
        client.close()
        server.stop()
    }

    private fun createTlsContexts(): Pair<javax.net.ssl.SSLContext, javax.net.ssl.SSLContext> {
        val loader = Thread.currentThread().contextClassLoader
        val certPath = Paths.get(loader.getResource("server.crt")!!.toURI()).toString()
        val keyPath = Paths.get(loader.getResource("server.key")!!.toURI()).toString()
        return createTestSslContexts(certPath, keyPath)
    }
}
