//go:build !windows

package api

import (
	"fmt"
	"os"
	"strings"
	"time"
)

// collectSystemMetrics reads /proc on Linux. On macOS / BSD this returns
// zeroes for files that don't exist — the dashboard panel renders blanks
// rather than crashing. macOS-specific metrics could be added later via
// `vm_stat` / `iostat` parsing.
func collectSystemMetrics() sysMetrics {
	m := sysMetrics{}

	// CPU from /proc/stat
	if data, err := os.ReadFile("/proc/stat"); err == nil {
		line := strings.Split(string(data), "\n")[0]
		fields := strings.Fields(line)
		if len(fields) >= 5 {
			var idle, total float64
			for i := 1; i < len(fields) && i <= 4; i++ {
				var v float64
				fmt.Sscanf(fields[i], "%f", &v)
				total += v
				if i == 4 {
					idle = v
				}
			}
			if lastCPUSet {
				dIdle := idle - lastCPU[0]
				dTotal := total - lastCPU[1]
				if dTotal > 0 {
					m.CPUPercent = (1 - dIdle/dTotal) * 100
				}
			}
			lastCPU = [2]float64{idle, total}
			lastCPUSet = true
		}
	}

	// Memory from /proc/meminfo
	if data, err := os.ReadFile("/proc/meminfo"); err == nil {
		var memTotal, memAvailable float64
		for _, line := range strings.Split(string(data), "\n") {
			fields := strings.Fields(line)
			if len(fields) < 2 {
				continue
			}
			var v float64
			fmt.Sscanf(fields[1], "%f", &v)
			switch fields[0] {
			case "MemTotal:":
				memTotal = v
			case "MemAvailable:":
				memAvailable = v
			}
		}
		if memTotal > 0 {
			m.MemTotalMB = memTotal / 1024
			m.MemUsedMB = (memTotal - memAvailable) / 1024
			m.MemPercent = (memTotal - memAvailable) / memTotal * 100
		}
	}

	// Network from /proc/net/dev
	if data, err := os.ReadFile("/proc/net/dev"); err == nil {
		var rxBytes, txBytes float64
		for _, line := range strings.Split(string(data), "\n")[2:] {
			fields := strings.Fields(line)
			if len(fields) < 10 {
				continue
			}
			iface := strings.TrimSuffix(fields[0], ":")
			if iface == "lo" {
				continue
			}
			var rx, tx float64
			fmt.Sscanf(fields[1], "%f", &rx)
			fmt.Sscanf(fields[9], "%f", &tx)
			rxBytes += rx
			txBytes += tx
		}
		now := time.Now()
		if !lastNetTs.IsZero() {
			elapsed := now.Sub(lastNetTs).Seconds()
			if elapsed > 0 {
				m.NetRxKBs = (rxBytes - lastNet[0]) / 1024 / elapsed
				m.NetTxKBs = (txBytes - lastNet[1]) / 1024 / elapsed
				if m.NetRxKBs < 0 {
					m.NetRxKBs = 0
				}
				if m.NetTxKBs < 0 {
					m.NetTxKBs = 0
				}
			}
		}
		lastNet = [2]float64{rxBytes, txBytes}
		lastNetTs = now
	}

	return m
}
