package collector

import (
	"os/exec"
	"strconv"
	"strings"
	"time"
)

type CPUInfo struct {
	Model        string  `json:"model"`
	Cores        int     `json:"cores"`
	Threads      int     `json:"threads"`
	FreqMHz      int     `json:"freq_mhz"`
	UsagePercent float64 `json:"usage_percent"`
}

func CollectCPU() CPUInfo {
	info := CPUInfo{}

	// CPU Model
	info.Model = sysctlGet("hw.model")

	// Anzahl CPUs (Threads)
	if v, err := strconv.Atoi(sysctlGet("hw.ncpu")); err == nil {
		info.Threads = v
	}

	// Kerne - versuche kern.smp.cores, Fallback auf ncpu
	if v, err := strconv.Atoi(sysctlGet("kern.smp.cores")); err == nil && v > 0 {
		info.Cores = v
	} else {
		info.Cores = info.Threads
	}

	// Frequenz in MHz
	if v, err := strconv.Atoi(sysctlGet("dev.cpu.0.freq")); err == nil {
		info.FreqMHz = v
	}

	// CPU-Auslastung via kern.cp_time (zwei Messungen im Abstand von 1 Sekunde)
	info.UsagePercent = measureCPUUsage()

	return info
}

func sysctlGet(key string) string {
	out, err := exec.Command("sysctl", "-n", key).Output()
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(out))
}

// measureCPUUsage misst die CPU-Auslastung ueber kern.cp_time
// Format: user nice sys intr idle
func measureCPUUsage() float64 {
	parse := func() (idle, total int64, ok bool) {
		out := sysctlGet("kern.cp_time")
		if out == "" {
			return 0, 0, false
		}
		fields := strings.Fields(out)
		if len(fields) < 5 {
			return 0, 0, false
		}
		var vals [5]int64
		for i := 0; i < 5; i++ {
			v, err := strconv.ParseInt(fields[i], 10, 64)
			if err != nil {
				return 0, 0, false
			}
			vals[i] = v
		}
		// user + nice + sys + intr + idle
		total = vals[0] + vals[1] + vals[2] + vals[3] + vals[4]
		idle = vals[4]
		return idle, total, true
	}

	idle1, total1, ok1 := parse()
	if !ok1 {
		return 0
	}

	time.Sleep(1 * time.Second)

	idle2, total2, ok2 := parse()
	if !ok2 {
		return 0
	}

	totalDelta := float64(total2 - total1)
	if totalDelta == 0 {
		return 0
	}

	idleDelta := float64(idle2 - idle1)
	usage := (1.0 - idleDelta/totalDelta) * 100.0

	if usage < 0 {
		usage = 0
	}
	if usage > 100 {
		usage = 100
	}

	return usage
}
