//go:build windows

package client

import (
	"encoding/json"
	"math"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"unsafe"
)

// collectResourcePressure gathers disk, CPU throttle, and GPU metrics on Windows.
func collectResourcePressure() *ResourcePressure {
	r := &ResourcePressure{}

	// ── Disk free space ───────────────────────────────────────────────────────
	// Check the drive that hosts the running binary.
	exe, _ := os.Executable()
	if exe == "" {
		exe = `C:\`
	}
	freeGB, totalGB, freePct := winDiskStats(filepath.VolumeName(exe))
	if freePct >= 0 {
		r.DiskFreeGB = &freeGB
		r.DiskTotalGB = &totalGB
		r.DiskFreePct = &freePct
	}

	// ── CPU frequency via short PowerShell call ───────────────────────────────
	const cpuScript = `$c=Get-CimInstance Win32_Processor|Select-Object -First 1 CurrentClockSpeed,MaxClockSpeed;@{freq=[int]$c.CurrentClockSpeed;max=[int]$c.MaxClockSpeed}|ConvertTo-Json -Compress`
	if out, err := silentOutput("powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command", cpuScript); err == nil {
		var m map[string]interface{}
		if json.Unmarshal([]byte(strings.TrimSpace(string(out))), &m) == nil {
			if freq, ok := m["freq"].(float64); ok && freq > 0 {
				n := int(freq)
				r.CPUFreqMHz = &n
			}
			if max, ok := m["max"].(float64); ok && max > 0 {
				n := int(max)
				r.CPUMaxMHz = &n
				if r.CPUFreqMHz != nil {
					throttled := float64(*r.CPUFreqMHz) < float64(n)*0.80
					r.CPUThrottle = &throttled
				}
			}
		}
	}

	// ── GPU (NVIDIA) ──────────────────────────────────────────────────────────
	r.GPUTempC, r.GPUUsagePct = probeGPU()

	return r
}

// winDiskStats returns (freeGB, totalGB, freePct) for the given drive letter root.
// e.g. pass "C:" — the function appends the backslash.
// Returns freePct = -1 on failure.
func winDiskStats(volumeName string) (freeGB, totalGB float64, freePct int) {
	root := volumeName
	if root == "" {
		root = "C:"
	}
	root += `\`

	kernel32 := syscall.NewLazyDLL("kernel32.dll")
	getDiskFreeSpaceEx := kernel32.NewProc("GetDiskFreeSpaceExW")

	rootPtr, err := syscall.UTF16PtrFromString(root)
	if err != nil {
		return 0, 0, -1
	}

	var freeAvail, total, totalFree uint64
	ret, _, _ := getDiskFreeSpaceEx.Call(
		uintptr(unsafe.Pointer(rootPtr)),
		uintptr(unsafe.Pointer(&freeAvail)),
		uintptr(unsafe.Pointer(&total)),
		uintptr(unsafe.Pointer(&totalFree)),
	)
	if ret == 0 || total == 0 {
		return 0, 0, -1
	}

	const gb = 1024 * 1024 * 1024
	freeGB = math.Round(float64(freeAvail)/gb*100) / 100
	totalGB = math.Round(float64(total)/gb*100) / 100
	freePct = int(float64(freeAvail) / float64(total) * 100)
	return
}
