// Package sysinfo collects host metadata at agent startup: OS, arch,
// hostname, restic version. The agent sends this in `hello` so the
// server's Host row stays current.
package sysinfo

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"gitea.dcglab.co.uk/steve/restic-manager/internal/api"
)

// Snapshot is the bundle of metadata reported in `hello`.
type Snapshot struct {
	Hostname        string
	OS              api.HostOS
	Arch            api.HostArch
	ResticVersion   string
	ProtocolVersion int
	BootTime        time.Time
}

// Collect probes the running host. resticPath, if non-empty,
// overrides PATH lookup.
func Collect(ctx context.Context, resticPath string) (Snapshot, error) {
	hn, err := os.Hostname()
	if err != nil {
		return Snapshot{}, fmt.Errorf("sysinfo: hostname: %w", err)
	}

	osTag := api.HostOS(runtime.GOOS)
	archTag := api.HostArch(runtime.GOARCH)

	resticVer, _ := detectResticVersion(ctx, resticPath) // empty on failure is fine
	return Snapshot{
		Hostname:        hn,
		OS:              osTag,
		Arch:            archTag,
		ResticVersion:   resticVer,
		ProtocolVersion: api.CurrentProtocolVersion,
	}, nil
}

// detectResticVersion runs `restic version` and parses the first line.
// Output looks like:
//
//	restic 0.17.1 compiled with go1.22.5 on linux/amd64
//
// Returns the version token (e.g. "0.17.1") or "" if restic isn't
// found. We never block startup on a missing restic — the operator
// might not have installed it yet, and the agent should still be
// able to connect and report.
func detectResticVersion(ctx context.Context, override string) (string, error) {
	bin := override
	if bin == "" {
		var err error
		bin, err = exec.LookPath("restic")
		if err != nil {
			return "", err
		}
	}

	versionCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()
	out, err := exec.CommandContext(versionCtx, bin, "version").Output()
	if err != nil {
		return "", err
	}
	first := strings.SplitN(strings.TrimSpace(string(out)), "\n", 2)[0]
	parts := strings.Fields(first)
	if len(parts) >= 2 && parts[0] == "restic" {
		return parts[1], nil
	}
	return "", fmt.Errorf("sysinfo: unrecognised restic version output: %q", first)
}
