package io.stellarfrontier.stellarplugin

import org.java_websocket.client.WebSocketClient
import org.java_websocket.handshake.ServerHandshake
import java.net.URI
import java.util.logging.Logger
import java.util.concurrent.ConcurrentLinkedQueue

class SocketClient(uri: URI, private val logger: Logger) : WebSocketClient(uri) {

    private @Volatile var shouldReconnect = true

    private val messageQueue = ConcurrentLinkedQueue<String>()
    private val lock = Any()
    
    // Callbacks for events
    private var configHandler: ((List<String>) -> Unit)? = null

    fun setConfigHandler(handler: (List<String>) -> Unit) {
        configHandler = handler
    }

    fun shutdown() {
        shouldReconnect = false
        close()
    }

    override fun onOpen(handshakedata: ServerHandshake?) {
        logger.info("Connected to WebSocket server")
        // Socket.IO connection is established when we receive the Open packet (0)
        // We must send the Connect packet (40) to join the default namespace
        send("40")
        logger.info("Sent Socket.IO Connect packet")

        flushQueue()
    }

    private fun flushQueue() {
        synchronized(lock) {
            while (!messageQueue.isEmpty()) {
                val msg = messageQueue.poll()
                send(msg)
                logger.info("Flushed queued message: $msg")
            }
        }
    }

    override fun onMessage(message: String?) {
        if (message == "2") {
            send("3")
            return
        }
        logger.info("Received message: $message")
        
        // Basic parsing for config_update
        // Format: 42["config_update",{"enabled_events":["Event1", "Event2"]}]
        if (message != null && message.startsWith("42[\"config_update\"")) {
            try {
                val jsonPart = message.substring(message.indexOf(',') + 1, message.lastIndexOf(']'))
                // We could use Gson here but let's do simple parsing or use the Gson instance in UniversalListener?
                // Actually we just added Gson dependency so use it.
                // But SocketClient doesn't have Gson instance. Reference it? Or manual parsing to avoid complexity?
                // Let's use simple manual parsing for now as it's just one list.
                // Or better, let UniversalListener handle parsing if we pass the raw string?
                // No, nicer to pass the list.
                
                // Let's rely on string manipulation for the list of strings since it's cleaner than adding Gson property here
                if (jsonPart.contains("enabled_events")) {
                     val listPart = jsonPart.substringAfter("[\"").substringBefore("\"]")
                     val events = listPart.split("\",\"")
                     configHandler?.invoke(events)
                }
            } catch (e: Exception) {
                logger.warning("Failed to parse config update: ${e.message}")
            }
        }
    }
    
    fun sendSocketEvent(eventName: String, jsonObject: String) {
        val packet = "42[\"$eventName\",$jsonObject]"
        if (isOpen) {
            logger.info("Sending event directly (via queue): $packet")
            messageQueue.add(packet)
            flushQueue()
        } else {
            messageQueue.add(packet)
            logger.info("Connection closed, queued event: $packet")
        }
    }

    override fun onClose(code: Int, reason: String?, remote: Boolean) {
        if (shouldReconnect) {
            logger.info("Disconnected from WebSocket server: $reason. Reconnecting in 5 seconds...")
            Thread {
                try {
                    Thread.sleep(5000)
                    reconnect()
                } catch (e: Exception) {
                    logger.severe("Failed to reconnect: ${e.message}")
                }
            }.start()
        } else {
            logger.info("Disconnected from WebSocket server: $reason")
        }
    }

    override fun onError(ex: Exception?) {
        logger.severe("WebSocket error: ${ex?.message}")
    }
}
