//go:build !windows

package client

import (
	"os"
	"os/exec"
	"os/user"
	"runtime"
	"strconv"
	"strings"
)

func collectSysCheckPlatform(r *FullSysCheckReport) {
	hw := &SysCheckHardware{}

	if out, err := exec.Command("uname", "-a").CombinedOutput(); err == nil {
		parts := strings.Fields(string(out))
		if len(parts) >= 3 {
			hw.Manufacturer = parts[2]
		}
	}

	if runtime.GOOS == "darwin" {
		if out, err := exec.Command("sysctl", "-n", "hw.model").CombinedOutput(); err == nil {
			hw.Model = strings.TrimSpace(string(out))
		}
		if out, err := exec.Command("sysctl", "-n", "hw.memsize").CombinedOutput(); err == nil {
			if n, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64); err == nil {
				hw.MemoryGB = float64(n) / (1024 * 1024 * 1024)
			}
		}
	} else {
		if out, err := exec.Command("sh", "-c", "grep -m1 'model name' /proc/cpuinfo | cut -d: -f2").CombinedOutput(); err == nil {
			hw.CPUs = []SysCheckCPU{{Name: strings.TrimSpace(string(out))}}
		}
		if out, err := exec.Command("sh", "-c", "grep -c ^processor /proc/cpuinfo").CombinedOutput(); err == nil {
			if n, err := strconv.Atoi(strings.TrimSpace(string(out))); err == nil && len(hw.CPUs) > 0 {
				hw.CPUs[0].Logical = n
			}
		}
		if out, err := exec.Command("free", "-b").CombinedOutput(); err == nil {
			lines := strings.Split(string(out), "\n")
			if len(lines) > 1 {
				fields := strings.Fields(lines[1])
				if len(fields) >= 2 {
					if total, err := strconv.ParseInt(fields[1], 10, 64); err == nil {
						hw.MemoryGB = float64(total) / (1024 * 1024 * 1024)
					}
				}
			}
		}
	}

	if out, err := exec.Command("df", "-h").CombinedOutput(); err == nil {
		hw.Disks = parseDfOutput(string(out))
	}

	if out, err := exec.Command("sh", "-c", "cat /proc/uptime 2>/dev/null || sysctl -n kern.boottime 2>/dev/null").CombinedOutput(); err == nil {
		fields := strings.Fields(string(out))
		if len(fields) > 0 {
			if sec, err := strconv.ParseFloat(fields[0], 64); err == nil {
				hw.UptimeHours = sec / 3600
			}
		}
	}

	r.Hardware = hw

	if r.Identity == nil {
		r.Identity = &SysCheckIdentity{}
	}
	if u, err := user.Current(); err == nil {
		r.Identity.Username = u.Username
	}
	r.Identity.MACAddress = primaryMACAddress()

	if r.Environment == nil {
		r.Environment = &SysCheckEnvironment{}
	}
	r.Environment.HomeDir = os.Getenv("HOME")
	r.Environment.TempDir = os.Getenv("TMPDIR")
	if r.Environment.TempDir == "" {
		r.Environment.TempDir = "/tmp"
	}

	if r.Network == nil {
		r.Network = &SysCheckNetwork{}
	}
	if out, err := exec.Command("sh", "-c", "ip route show default 2>/dev/null || route -n get default 2>/dev/null").CombinedOutput(); err == nil {
		r.Network.RoutesSummary = strings.TrimSpace(string(out))
		for _, line := range strings.Split(string(out), "\n") {
			if strings.Contains(line, "via") || strings.Contains(line, "gateway:") {
				fields := strings.Fields(line)
				for i, f := range fields {
					if f == "via" && i+1 < len(fields) {
						r.Network.DefaultGateway = fields[i+1]
						break
					}
					if strings.HasPrefix(f, "gateway:") {
						r.Network.DefaultGateway = strings.TrimPrefix(f, "gateway:")
						break
					}
				}
				break
			}
		}
	}
}

func parseDfOutput(raw string) []SysCheckDisk {
	var disks []SysCheckDisk
	for _, line := range strings.Split(raw, "\n")[1:] {
		fields := strings.Fields(line)
		if len(fields) < 6 {
			continue
		}
		mount := fields[len(fields)-1]
		disks = append(disks, SysCheckDisk{
			Mount:   mount,
			FSType:  fields[0],
			TotalGB: parseSizeGB(fields[1]),
			FreeGB:  parseSizeGB(fields[3]),
		})
	}
	return disks
}

func parseSizeGB(s string) float64 {
	s = strings.TrimSuffix(s, "G")
	s = strings.TrimSuffix(s, "T")
	s = strings.TrimSuffix(s, "M")
	f, _ := strconv.ParseFloat(s, 64)
	if strings.HasSuffix(s, "T") {
		return f * 1024
	}
	return f
}
