package com.nhnkcp.verifonepossample

import android.util.Log
import kotlinx.coroutines.withTimeout
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.net.InetSocketAddress
import java.net.Socket

object SocketConnection {
    private const val TIMEOUT = 30000

    private var socket: Socket? = null
    private var inputStream: InputStream? = null
    private var outputStream: OutputStream? = null
    private var socketThread: Thread? = null

    suspend fun connect(serverIp: String, serverPort: Int): Boolean {
        return runCatching {
            val socketAddress = InetSocketAddress(serverIp, serverPort)
            socket = Socket()
            socket?.connect(socketAddress, 30000)
            inputStream = socket?.getInputStream()
            outputStream = socket?.getOutputStream()
        }.fold(
            onSuccess = {
                Log.d("SocketConnection", "Connected to $serverIp $serverPort")
                startReceiveThread()
                true
            },
            onFailure = {
                it.printStackTrace()
                false
            }
        )
    }

    fun disconnect() {
        runCatching {
            inputStream?.close()
            outputStream?.close()
            socket?.close()
        }.onSuccess {
            Log.d("SocketConnection", "Disconnected")
        }.onFailure {
            it.printStackTrace()
        }
    }

    suspend fun sendData(data: ByteArray): Boolean {
        return runCatching {
            withTimeout(TIMEOUT.toLong()) {
                outputStream?.write(data)
                outputStream?.flush()
            }
        }.fold(
            onSuccess = {
                Log.d("SocketConnection", "Data sent: ${String(data).trim()}")
                true
            },
            onFailure = {
                it.printStackTrace()
                false
            }
        )
    }

    @Synchronized
    fun startReceiveThread() {
        if(inputStream == null) {
            Log.e("SocketConnection", "Can't open inputStream")
            return
        }

        if(socketThread != null) return

        socketThread = Thread {
            while(true) {
                try {
                    Thread.sleep(50)
                } catch (e: Exception) {
                    socketThread?.interrupt()
                    return@Thread
                }

                if(inputStream != null) {
                    val byteArrayOutputStream = ByteArrayOutputStream()
                    val buffer = ByteArray(4096)
                    var bytesRead = 0

                    while(inputStream!!.available() > 0) {
                        try {
                            bytesRead = inputStream!!.read(buffer)
                        } catch (e: Exception) {
                            e.printStackTrace()
                        }

                        if(bytesRead > 0) {
                            byteArrayOutputStream.write(buffer, 0, bytesRead)
                        }

                        if(byteArrayOutputStream.size() > 0 && bytesRead > 0) {
                            Log.d("SocketConnection", "Data received ${String(byteArrayOutputStream.toByteArray()).trim()}")
                        }
                    }
                }
            }
        }

        socketThread?.start()

//        runCatching {
//            withTimeout(TIMEOUT.toLong()) {
//                Log.d("SocketConnection", "Data received 11 ${inputStream?.available()}")
//
//                while ((inputStream?.available() ?: 0) > 0) {
//                    val bytesRead = runCatching { inputStream?.read(buffer) ?: -1 }.getOrDefault(0)
//                    Log.d("SocketConnection", "Data received 22 ${bytesRead}")
//
//                    if (bytesRead > 0) {
//                        val result = buffer.copyOf(bytesRead)
//                        outputStream?.write(result)
//                        Log.d("SocketConnection", "Data received ${String(result).trim()}")
//                   //     emit(result) // 받은 데이터를 flow로 방출
//                    }
//                }
//            }
//        }.onFailure {
//            it.printStackTrace()
//         //   emit(null) // 실패 시 null 방출
//        }
    }

    fun isConnected(): Boolean {
        return socket?.isConnected == true
    }
}