package com.optix.android.tools.network

import com.optix.android.domain.model.HostResult
import com.optix.android.domain.model.ParamType
import com.optix.android.domain.model.ToolCategory
import com.optix.android.domain.model.ToolEvent
import com.optix.android.domain.model.ToolMetadata
import com.optix.android.domain.model.ToolParam
import com.optix.android.tools.registry.BaseTool
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress

class NetbiosScannerTool : BaseTool() {

    override val metadata = ToolMetadata(
        name = "netbios_scanner",
        displayName = "NetBIOS Scanner",
        description = "Query NetBIOS name table on target hosts (UDP 137)",
        category = ToolCategory.NETWORK_SCANNING,
        parameters = listOf(
            ToolParam("target", ParamType.STRING, "Target IP or CIDR range"),
            ToolParam("timeout_ms", ParamType.INT, "UDP timeout (ms)", required = false, defaultValue = "1000"),
        ),
    )

    override suspend fun execute(params: Map<String, Any>, emit: suspend (ToolEvent) -> Unit) {
        val target = paramRequired(params, "target")
        val timeoutMs = paramInt(params, "timeout_ms", 1000)

        emit(ToolEvent.Log("NetBIOS scan: $target"))

        withContext(Dispatchers.IO) {
            var socket: DatagramSocket? = null
            runCatching {
                socket = DatagramSocket()
                socket?.soTimeout = timeoutMs
                val addr = InetAddress.getByName(target)
                // NetBIOS Name Service query packet
                val query = byteArrayOf(
                    0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41,
                    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
                    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
                    0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
                    0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21, 0x00, 0x01,
                )
                socket?.send(DatagramPacket(query, query.size, addr, 137))
                val buf = ByteArray(1024)
                val response = DatagramPacket(buf, buf.size)
                socket?.receive(response)
                val hostname = String(buf, 57, 15).trim()
                emit(ToolEvent.Result(HostResult(ip = target, hostname = hostname, status = "UP")))
                emit(ToolEvent.Log("  $target  NetBIOS name: $hostname"))
            }.onFailure {
                emit(ToolEvent.Log("  $target  No NetBIOS response"))
            }

            socket?.close()
        }

        emit(ToolEvent.ChainSuggestion("nmap_termux", mapOf("target" to target)))
        emit(ToolEvent.Done)
    }
}
