package sentinel

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

// Snapshot captures host-level facts.
type Snapshot struct {
	Hostname      string            `json:"hostname,omitempty"`
	Kernel        string            `json:"kernel,omitempty"`
	OSImage       string            `json:"os_image,omitempty"`
	K3sVersion    string            `json:"k3s_version,omitempty"`
	Containerd    string            `json:"containerd,omitempty"`
	PackageSample map[string]string `json:"package_sample,omitempty"` // small subset to detect drift
	DropInsSample map[string]string `json:"dropins_sample,omitempty"` // path->content hash/sample
	Notes         string            `json:"notes,omitempty"`
}

// Collect gathers a minimal set of facts; intended to run inside a DaemonSet pod with host mounts.
func Collect() *Snapshot {
	return &Snapshot{
		Hostname:      runAndTrim("hostname"),
		Kernel:        runAndTrim("uname", "-r"),
		OSImage:       osRelease(),
		K3sVersion:    runAndTrim("k3s", "version"),
		Containerd:    runAndTrim("containerd", "--version"),
		PackageSample: pkgSample(),
	}
}

func runAndTrim(cmd string, args ...string) string {
	out, err := commandOutput(cmd, args...)
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(out))
}

func osRelease() string {
	out, err := commandOutput("cat", "/etc/os-release")
	if err != nil {
		return ""
	}
	for _, line := range strings.Split(string(out), "\n") {
		if strings.HasPrefix(line, "PRETTY_NAME=") {
			return strings.Trim(line[len("PRETTY_NAME="):], "\"")
		}
	}
	return ""
}

// pkgSample grabs a tiny subset of package versions to detect drift without collecting everything.
func pkgSample() map[string]string {
	names := []string{"containerd", "k3s", "nvidia-container-toolkit", "linux-image-raspi"}
	result := map[string]string{}
	for _, n := range names {
		v := pkgVersion(n)
		if v != "" {
			result[n] = v
		}
	}
	return result
}

func pkgVersion(name string) string {
	// Try dpkg-query first.
	out, err := commandOutput("dpkg-query", "-W", "-f", "${Version}", name)
	if err == nil && len(out) > 0 {
		return strings.TrimSpace(string(out))
	}
	// Fallback rpm.
	out, err = commandOutput("rpm", "-q", "--qf", "%{VERSION}-%{RELEASE}", name)
	if err == nil && len(out) > 0 {
		return strings.TrimSpace(string(out))
	}
	return ""
}

func commandOutput(cmd string, args ...string) ([]byte, error) {
	if os.Getenv("METIS_SENTINEL_NSENTER") == "1" {
		nsenterArgs := []string{"-t", "1", "-m", "-u", "-n", "-i", "-p", "--", cmd}
		nsenterArgs = append(nsenterArgs, args...)
		return exec.Command("nsenter", nsenterArgs...).Output()
	}
	return exec.Command(cmd, args...).Output()
}
