package monitor

import (
	"context"
	"time"

	"github.com/shirou/gopsutil/v3/cpu"
	"github.com/shirou/gopsutil/v3/mem"
	psnet "github.com/shirou/gopsutil/v3/net"
)

// Stats is a single telemetry snapshot.
// Percent values are 0..100.
// NetUpBps / NetDownBps are bytes per second.
type Stats struct {
	CPU       float64
	RAM       float64
	NetUpBps  float64
	NetDownBps float64
	TS        time.Time
}

// Start collects system stats periodically until ctx is cancelled.
// It emits Stats into out. The caller is expected to close(out) after Start returns.
func Start(ctx context.Context, out chan<- Stats) {
	ticker := time.NewTicker(500 * time.Millisecond)
	defer ticker.Stop()

	var lastSent time.Time
	var lastUp uint64
	var lastDown uint64
	var hasLast bool

	readNet := func() (up, down uint64, ok bool) {
		ios, err := psnet.IOCounters(false)
		if err != nil || len(ios) == 0 {
			return 0, 0, false
		}
		// bytes sent = upload, bytes recv = download
		return ios[0].BytesSent, ios[0].BytesRecv, true
	}

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			ts := time.Now()

			// CPU
			c, err := cpu.Percent(0, false)
			cpuPct := 0.0
			if err == nil && len(c) > 0 {
				cpuPct = c[0]
			}

			// Memory
			m, err := mem.VirtualMemory()
			ramPct := 0.0
			if err == nil && m != nil {
				ramPct = m.UsedPercent
			}

			// Network (bytes per second)
			upBps := 0.0
			downBps := 0.0
			if up, down, ok := readNet(); ok {
				if hasLast {
					dt := ts.Sub(lastSent).Seconds()
					if dt > 0 {
						upBps = float64(up-lastUp) / dt
						downBps = float64(down-lastDown) / dt
					}
				}
				lastUp, lastDown = up, down
				lastSent = ts
				hasLast = true
			}

			out <- Stats{
				CPU:        cpuPct,
				RAM:        ramPct,
				NetUpBps:   upBps,
				NetDownBps: downBps,
				TS:         ts,
			}
		}
	}
}
