//go:build windows
// +build windows

package sys

import (
	"errors"
	"sync"
	"syscall"
	"unsafe"

	"github.com/shirou/gopsutil/v4/net"
)

func GetConnectionCount(proto string) (int, error) {
	if proto != "tcp" && proto != "udp" {
		return 0, errors.New("invalid protocol")
	}

	stats, err := net.Connections(proto)
	if err != nil {
		return 0, err
	}
	return len(stats), nil
}

func GetTCPCount() (int, error) {
	return GetConnectionCount("tcp")
}

func GetUDPCount() (int, error) {
	return GetConnectionCount("udp")
}

// --- CPU Utilization (Windows native) ---

var (
	modKernel32        = syscall.NewLazyDLL("kernel32.dll")
	procGetSystemTimes = modKernel32.NewProc("GetSystemTimes")

	cpuMu      sync.Mutex
	lastIdle   uint64
	lastKernel uint64
	lastUser   uint64
	hasLast    bool
)

type filetime struct {
	LowDateTime  uint32
	HighDateTime uint32
}

func ftToUint64(ft filetime) uint64 {
	return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
}

// CPUPercentRaw returns the instantaneous total CPU utilization percentage using
// Windows GetSystemTimes across all logical processors. The first call returns 0
// as it initializes the baseline. Subsequent calls compute deltas.
func CPUPercentRaw() (float64, error) {
	var idleFT, kernelFT, userFT filetime
	r1, _, e1 := procGetSystemTimes.Call(
		uintptr(unsafe.Pointer(&idleFT)),
		uintptr(unsafe.Pointer(&kernelFT)),
		uintptr(unsafe.Pointer(&userFT)),
	)
	if r1 == 0 { // failure
		if e1 != nil {
			return 0, e1
		}
		return 0, syscall.GetLastError()
	}

	idle := ftToUint64(idleFT)
	kernel := ftToUint64(kernelFT)
	user := ftToUint64(userFT)

	cpuMu.Lock()
	defer cpuMu.Unlock()

	if !hasLast {
		lastIdle = idle
		lastKernel = kernel
		lastUser = user
		hasLast = true
		return 0, nil
	}

	idleDelta := idle - lastIdle
	kernelDelta := kernel - lastKernel
	userDelta := user - lastUser

	// Update for next call
	lastIdle = idle
	lastKernel = kernel
	lastUser = user

	total := kernelDelta + userDelta
	if total == 0 {
		return 0, nil
	}
	// On Windows, kernel time includes idle time; busy = total - idle
	busy := total - idleDelta

	pct := float64(busy) / float64(total) * 100.0
	// lower bound not needed; ratios of uint64 are non-negative
	if pct > 100 {
		pct = 100
	}
	return pct, nil
}
