//go:build windows

package client

import (
	"encoding/json"
	"strings"
)

// collectListenPorts returns all TCP listeners on this Windows host.
// Uses Get-NetTCPConnection (fast, built into Win8+/2012+) with per-port
// process name lookup via Get-Process.
func collectListenPorts() *ListenPortsReport {
	const script = `
$ErrorActionPreference = 'SilentlyContinue'
$procs = @{}
Get-Process | ForEach-Object { $procs[[int]$_.Id] = $_.ProcessName }
$ports = Get-NetTCPConnection -State Listen | ForEach-Object {
  $pname = if ($_.OwningProcess -and $procs.ContainsKey([int]$_.OwningProcess)) {
    $procs[[int]$_.OwningProcess]
  } else { '' }
  [ordered]@{
    port    = [int]$_.LocalPort
    addr    = $_.LocalAddress
    proto   = 'tcp'
    process = $pname
    pid     = [int]$_.OwningProcess
  }
} | Sort-Object { $_['port'] } -Unique
@{ ports = @($ports); count = @($ports).Count } | ConvertTo-Json -Depth 3 -Compress
`
	r := &ListenPortsReport{}
	out, err := silentOutput("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command", script)
	if err != nil {
		return r
	}
	raw := strings.TrimSpace(string(out))
	if idx := strings.LastIndex(raw, "{"); idx > 0 {
		raw = raw[idx:]
	}
	var m map[string]interface{}
	if json.Unmarshal([]byte(raw), &m) != nil {
		return r
	}
	if arr, ok := m["ports"].([]interface{}); ok {
		for _, item := range arr {
			obj, ok := item.(map[string]interface{})
			if !ok {
				continue
			}
			lp := ListenPort{Proto: "tcp"}
			if v, ok := obj["port"].(float64); ok {
				lp.Port = int(v)
			}
			if v, ok := obj["addr"].(string); ok {
				lp.Addr = v
			}
			if v, ok := obj["process"].(string); ok {
				lp.Process = v
			}
			if v, ok := obj["pid"].(float64); ok {
				lp.PID = int(v)
			}
			if lp.Port > 0 {
				r.Ports = append(r.Ports, lp)
			}
		}
	}
	r.Count = len(r.Ports)
	return r
}
