package metrics

import (
	"strconv"

	"github.com/prometheus/client_golang/prometheus"
	"libvirt.org/go/libvirt"
)

var (
	// Compute
	libvirtNodeCPUUsage = prometheus.NewDesc(
		prometheus.BuildFQName("libvirt", "node", "cpu_time_seconds_total"),
		"CPU usage of node",
		[]string{"hostname"},
		nil)

	libvirtNodeCPUTotal = prometheus.NewDesc(
		prometheus.BuildFQName("libvirt", "node", "cpu_threads"),
		"CPU usage of node",
		[]string{"hostname"},
		nil)

	libvirtNodeMemoryUsageBytes = prometheus.NewDesc(
		prometheus.BuildFQName("libvirt", "node", "memory_usage_bytes"),
		"Memory usage of the node, in bytes.",
		[]string{"hostname", "total"},
		nil)

	libvirtNodeMemoryTotalBytes = prometheus.NewDesc(
		prometheus.BuildFQName("libvirt", "node", "memory_total_bytes"),
		"Memory total of the node, in bytes.",
		[]string{"hostname"},
		nil)
)

/*type AvgStat struct {
	Load1  float64
	Load5  float64
	Load15 float64
}

func sysinfoAvgWithContext() (*AvgStat, error) {
	var info syscall.Sysinfo_t
	err := syscall.Sysinfo(&info)
	if err != nil {
		return nil, err
	}

	const si_load_shift = 16
	return &AvgStat{
		Load1:  float64(info.Loads[0]) / float64(1<<si_load_shift),
		Load5:  float64(info.Loads[1]) / float64(1<<si_load_shift),
		Load15: float64(info.Loads[2]) / float64(1<<si_load_shift),
	}, nil
}*/

func CollectNode(conn *libvirt.Connect, ch chan<- prometheus.Metric, hostname string) error {
	nodeInfo, _ := conn.GetNodeInfo()
	nodeCPU, _ := conn.GetCPUStats(int(libvirt.NODE_CPU_STATS_ALL_CPUS), 0) // rate(libvirt_node_cpu_time_seconds_total[10s]) * 100
	nodeMemory, _ := conn.GetMemoryStats(libvirt.NODE_MEMORY_STATS_ALL_CELLS, 0)

	ch <- prometheus.MustNewConstMetric(
		libvirtNodeCPUUsage,
		prometheus.CounterValue,
		float64(nodeCPU.Kernel+nodeCPU.User+nodeCPU.Iowait)/1e9, // From nsec to sec
		hostname,
	)

	ch <- prometheus.MustNewConstMetric(
		libvirtNodeCPUTotal,
		prometheus.GaugeValue,
		float64(nodeInfo.Sockets*nodeInfo.Cores*nodeInfo.Threads),
		hostname,
	)

	ch <- prometheus.MustNewConstMetric(
		libvirtNodeMemoryUsageBytes,
		prometheus.GaugeValue,
		float64(nodeMemory.Total-(nodeMemory.Buffers+nodeMemory.Free+nodeMemory.Cached))*1024,
		hostname,
		strconv.FormatInt(int64(nodeMemory.Total*1024), 10),
	)

	ch <- prometheus.MustNewConstMetric(
		libvirtNodeMemoryTotalBytes,
		prometheus.GaugeValue,
		float64(nodeMemory.Total)*1024,
		hostname,
	)

	return nil
}

func (e *LibvirtExporter) DescribeNode(ch chan<- *prometheus.Desc) {
	ch <- libvirtNodeCPUUsage
	ch <- libvirtNodeCPUTotal
	ch <- libvirtNodeMemoryUsageBytes
	ch <- libvirtNodeMemoryTotalBytes
}