package gupta

import (
	"fmt"
	"strconv"
	"strings"
)

const version = "0.0.1"

func Hello() string {
	return fmt.Sprintf("Welcome to gupta version %s", version)
}

func Run(load, cpu, memory bool, partition, networkInterface string) (cpuLoad, cpuUsage, memoryUsage float64) {
	cpuLoad = 0.2
	cpuUsage = 0.2
	memoryUsage = 70.0
	return cpuLoad, cpuUsage, memoryUsage
}

type GuptaReport struct {
	cpuLoad     float64
	cpuUsage    float64
	memoryUsage float64
}

func (g *GuptaReport) GetCPULoad() string {
	return fmt.Sprintf("%.2f", g.cpuLoad)
}

// collect all CPU stat from /proc/cpustat
type CPUStat struct {
	user         uint64
	nice         uint64
	system       uint64
	idle         uint64
	iowait       uint64
	idleNew      uint64
	iowaitNew    uint64
	irq          uint64
	softirq      uint64
	steal        uint64
	guest        uint64
	guest_nice   uint64
	totalTimeNew uint64
}

// parse the first line of /proc/cpustat without the word cpu
func (c *CPUStat) ReadInfo(rawInfo []string) {
	if s, err := strconv.ParseUint(rawInfo[0], 10, 64); err == nil {
		c.user = s
	}
	if s, err := strconv.ParseUint(rawInfo[1], 10, 64); err == nil {
		c.nice = s
	}
	if s, err := strconv.ParseUint(rawInfo[2], 10, 64); err == nil {
		c.system = s
	}
	if s, err := strconv.ParseUint(rawInfo[3], 10, 64); err == nil {
		c.idle = s
	}
	if s, err := strconv.ParseUint(rawInfo[4], 10, 64); err == nil {
		c.iowait = s
	}
	if s, err := strconv.ParseUint(rawInfo[5], 10, 64); err == nil {
		c.irq = s
	}
	if s, err := strconv.ParseUint(rawInfo[6], 10, 64); err == nil {
		c.softirq = s
	}
	if s, err := strconv.ParseUint(rawInfo[7], 10, 64); err == nil {
		c.steal = s
	}
	if s, err := strconv.ParseUint(rawInfo[8], 10, 64); err == nil {
		c.guest = s
	}
	if s, err := strconv.ParseUint(rawInfo[9], 10, 64); err == nil {
		c.guest_nice = s
	}
}

func (c *CPUStat) ReadInfoNew(rawInfo []string) {
	idleNew, _ := strconv.ParseUint(rawInfo[3], 10, 64)
	iowaitNew, _ := strconv.ParseUint(rawInfo[4], 10, 64)
	c.idleNew = idleNew
	c.iowaitNew = iowaitNew

	for _, s := range rawInfo {
		u, _ := strconv.ParseUint(s, 10, 64)
		c.totalTimeNew += u
	}
}

func (c *CPUStat) TotalTime() uint64 {
	return c.user + c.nice + c.system + c.idle + c.iowait + c.irq + c.softirq + c.steal
}

func (c *CPUStat) TotalTimeNew() uint64 {
	return c.totalTimeNew
}

func (c *CPUStat) IdleTime() uint64 {
	return c.idle + c.iowait
}

func (c *CPUStat) IdleTimeNew() uint64 {
	return c.idleNew + c.iowaitNew
}

func (c *CPUStat) CPUUsage() float64 {
	deltaIdleTime := c.IdleTimeNew() - c.IdleTime()
	deltaTotalTime := c.TotalTimeNew() - c.TotalTime()
	cpuUsage := (1.0 - float64(deltaIdleTime)/float64(deltaTotalTime)) * 100
	return cpuUsage
}

func NewCPUStat(procstatline, procstatlineNew string) CPUStat {
	cpustat := CPUStat{}
	statline := strings.Fields(procstatline)
	statlineNew := strings.Fields(procstatlineNew)

	cpustat.ReadInfo(statline[1:])
	cpustat.ReadInfoNew(statlineNew[1:])
	return cpustat
}