package profile

import (
	"fmt"
	//"runtime"
	"strings"
	"time"
)

type Options struct {
	UseSudo  bool
	Security bool
}

// Report is a human-readable system profile suitable for UI display and snapshot storage.
// Keep it text-first: parse later if/when you want structured JSON.
type Report struct {
	GeneratedAt time.Time
	//GoRuntime   string
	Kernel      string
	Distro      string
	Hardware    string
	Storage     string
	Network     string
	Security    string
	Notes       []string
}

func (r Report) String() string {
	var b strings.Builder
	b.WriteString(fmt.Sprintf("Generated: %s\n", r.GeneratedAt.Format("2006-01-02 15:04:05")))
	//if r.GoRuntime != "" {
		//b.WriteString(fmt.Sprintf("Go Runtime: %s\n", r.GoRuntime))
	//}
	if r.Distro != "" {
		b.WriteString("Distro: " + r.Distro + "\n")
	}
	if r.Kernel != "" {
		b.WriteString("Kernel: " + r.Kernel + "\n")
	}
	if len(r.Notes) > 0 {
		b.WriteString("\nNotes:\n")
		for _, n := range r.Notes {
			b.WriteString("- " + n + "\n")
		}
	}
	if r.Hardware != "" {
		b.WriteString("\n=== HARDWARE ===\n")
		b.WriteString(r.Hardware + "\n")
	}
	if r.Storage != "" {
		b.WriteString("\n=== STORAGE ===\n")
		b.WriteString(r.Storage + "\n")
	}
	if r.Network != "" {
		b.WriteString("\n=== NETWORK ===\n")
		b.WriteString(r.Network + "\n")
	}
	if r.Security != "" {
		b.WriteString("\n=== SECURITY ===\n")
		b.WriteString(r.Security + "\n")
	}
	return strings.TrimSpace(b.String())
}

// Collect gathers a system profile using authoritative OS commands.
// It is designed for Linux first.
func Collect(opt Options) Report {
	r := Runner{UseSudo: opt.UseSudo, Timeout: 3 * time.Second}

	//rep := Report{GeneratedAt: time.Now(), GoRuntime: runtime.Version()}
	rep := Report{GeneratedAt: time.Now()}

	// Distro + kernel
	// Prefer /etc/os-release (no external deps) via `sh -lc` is too hacky; use cat.
	osr := r.try("os-release", "cat", "/etc/os-release")
	if !strings.HasPrefix(osr, "os-release: ERROR") && !strings.Contains(osr, "os-release: sudo") {
		rep.Distro = parseOSReleasePretty(osr)
	}
	rep.Kernel = r.try("uname", "uname", "-a")

	// Hardware
	parts := []string{
		r.try("lscpu", "lscpu"),
		r.try("cpuinfo", "cat", "/proc/cpuinfo"),
		r.try("meminfo", "cat", "/proc/meminfo"),
		r.try("dmidecode", "dmidecode", "-t", "system"),
		r.try("dmidecode", "dmidecode", "-t", "bios"),
		r.try("dmidecode", "dmidecode", "-t", "baseboard"),
		r.try("lspci", "lspci", "-nnk"),
		r.try("lsusb", "lsusb"),
	}
	rep.Hardware = joinSections(parts)

	// Storage
	sParts := []string{
		r.try("lsblk", "lsblk", "-a", "-o", "NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINTS,UUID"),
		r.try("df", "df", "-hT"),
		r.try("mount", "mount"),
		r.try("fstab", "cat", "/etc/fstab"),
	}
	rep.Storage = joinSections(sParts)

	// Network
	nParts := []string{
		r.try("ip addr", "ip", "addr"),
		r.try("ip route", "ip", "route"),
		r.try("resolv", "cat", "/etc/resolv.conf"),
		r.try("ss", "ss", "-tulpn"),
	}
	rep.Network = joinSections(nParts)

	if opt.Security {
		secParts := []string{
			r.try("who", "who"),
			r.try("id", "id"),
			r.tryRaw("sudo -l", "sudo", "-n", "-l"),
			r.try("ufw", "ufw", "status", "verbose"),
			r.try("iptables", "iptables", "-S"),
			r.try("systemctl", "systemctl", "--no-pager", "--plain", "list-units", "--type=service", "--state=running"),
			r.try("tor", "systemctl", "--no-pager", "--plain", "status", "tor"),
		}
		rep.Security = joinSections(secParts)
	}

	if opt.UseSudo {
		rep.Notes = append(rep.Notes, "Sudo mode is ON (commands run via sudo -n). If you see 'sudo required', run `sudo -v` then Refresh.")
	} else {
		rep.Notes = append(rep.Notes, "Sudo mode is OFF (user-level inspection).")
	}
	if opt.Security {
		rep.Notes = append(rep.Notes, "Security introspection is ON.")
	}

	return rep
}

func joinSections(chunks []string) string {
	clean := make([]string, 0, len(chunks))
	for _, c := range chunks {
		c = strings.TrimSpace(c)
		if c == "" {
			continue
		}
		clean = append(clean, c)
	}
	return strings.Join(clean, "\n\n")
}

func parseOSReleasePretty(osRelease string) string {
	// Minimal parser: NAME + VERSION (or PRETTY_NAME if available)
	lines := strings.Split(osRelease, "\n")
	vals := map[string]string{}
	for _, ln := range lines {
		ln = strings.TrimSpace(ln)
		if ln == "" || strings.HasPrefix(ln, "#") {
			continue
		}
		k, v, ok := strings.Cut(ln, "=")
		if !ok {
			continue
		}
		v = strings.Trim(v, "\"")
		vals[k] = v
	}
	if p := vals["PRETTY_NAME"]; p != "" {
		return p
	}
	name := vals["NAME"]
	ver := vals["VERSION"]
	if name == "" {
		return ""
	}
	if ver == "" {
		return name
	}
	return name + " " + ver
}
