package com.wirelesstextsyncer.wireless_text_syncer_android

import android.content.Context
import android.net.wifi.WifiManager
import android.util.Log
import org.json.JSONObject
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress

object DiscoveryClient {
    private const val tag = "WTS"
    private const val discoveryPort = 8182
    private const val defaultServicePort = 8181

    fun discover(context: Context): List<DiscoveredService> {
        Log.d(tag, "Discovery started")
        val devices = mutableListOf<DiscoveredService>()
        val seen = mutableSetOf<String>()
        var multicastLock: WifiManager.MulticastLock? = null
        try {
            val wifi = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager
            multicastLock = wifi?.createMulticastLock("wireless-text-syncer-discovery")
            multicastLock?.setReferenceCounted(false)
            multicastLock?.acquire()

            DatagramSocket().use { socket ->
                socket.broadcast = true
                socket.soTimeout = 450
                val request = JSONObject()
                    .put("type", "wirelessTextSyncer.discovery")
                    .put("version", 1)
                    .toString()
                    .toByteArray(Charsets.UTF_8)
                val packet = DatagramPacket(
                    request,
                    request.size,
                    InetAddress.getByName("255.255.255.255"),
                    discoveryPort
                )
                socket.send(packet)

                val deadline = System.currentTimeMillis() + 1600
                while (System.currentTimeMillis() < deadline) {
                    try {
                        val buffer = ByteArray(2048)
                        val response = DatagramPacket(buffer, buffer.size)
                        socket.receive(response)
                        val json = JSONObject(String(response.data, 0, response.length, Charsets.UTF_8))
                        if (json.optString("type") != "wirelessTextSyncer.service") {
                            continue
                        }

                        val host = json.optString("host", response.address.hostAddress.orEmpty())
                        val port = json.optInt("port", defaultServicePort)
                        val key = "$host:$port"
                        if (seen.add(key)) {
                            Log.d(tag, "Discovery found ${json.optString("name", host)} $key")
                            devices += DiscoveredService(
                                name = json.optString("name", host),
                                host = host,
                                port = port
                            )
                        }
                    } catch (_: Exception) {
                    }
                }
            }
        } catch (exception: Exception) {
            Log.e(tag, "Discovery failed", exception)
        } finally {
            multicastLock?.let {
                if (it.isHeld) {
                    it.release()
                }
            }
        }

        Log.d(tag, "Discovery finished count=${devices.size}")
        return devices
    }
}

data class DiscoveredService(
    val name: String,
    val host: String,
    val port: Int
) {
    fun toMap(): Map<String, Any> {
        return mapOf(
            "name" to name,
            "host" to host,
            "port" to port
        )
    }
}
