package api

import (
	"bufio"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

func declareMonitorRoutes(router *gin.RouterGroup) {
	router.GET("/monitor", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"localhost": genLocalConstants(),
		})
	})
}

func readLoadAvg(fd *os.File) (ret map[string]float64) {
	if s, err := ioutil.ReadAll(fd); err == nil {
		f := strings.Fields(strings.TrimSpace(string(s)))
		if len(f) >= 3 {
			ret = map[string]float64{}
			ret["1m"], _ = strconv.ParseFloat(f[0], 64)
			ret["5m"], _ = strconv.ParseFloat(f[1], 64)
			ret["15m"], _ = strconv.ParseFloat(f[2], 64)
		}
	}
	return
}

func readMeminfo(fd *os.File) (ret map[string]uint64) {
	ret = map[string]uint64{}

	scanner := bufio.NewScanner(fd)
	for scanner.Scan() {
		f := strings.Fields(strings.TrimSpace(scanner.Text()))
		if len(f) >= 2 {
			if v, err := strconv.ParseUint(f[1], 10, 64); err == nil {
				ret[strings.ToLower(strings.TrimSuffix(f[0], ":"))] = v * 1024
			}
		}
	}

	return
}

func readCPUStats(fd *os.File) (ret map[string]map[string]uint64) {
	ret = map[string]map[string]uint64{}

	scanner := bufio.NewScanner(fd)
	for scanner.Scan() {
		f := strings.Fields(strings.TrimSpace(scanner.Text()))
		if len(f[0]) >= 4 && f[0][0:3] == "cpu" && len(f) >= 8 {
			ret[f[0]] = map[string]uint64{}
			var total uint64 = 0
			for i, k := range []string{"user", "nice", "system", "idle", "iowait", "irq", "softirq"} {
				if v, err := strconv.ParseUint(f[i+1], 10, 64); err == nil {
					ret[f[0]][k] = v
					total += v
				}
			}
			ret[f[0]]["total"] = total
		}
	}

	return
}

func genLocalConstants() interface{} {
	ret := map[string]interface{}{}

	fi, err := os.Open("/proc/loadavg")
	if err != nil {
		return err
	}
	defer fi.Close()
	ret["loadavg"] = readLoadAvg(fi)

	fi, err = os.Open("/proc/meminfo")
	if err != nil {
		return err
	}
	defer fi.Close()
	ret["meminfo"] = readMeminfo(fi)

	fi, err = os.Open("/proc/stat")
	if err != nil {
		return err
	}
	defer fi.Close()
	ret["cpustat"] = readCPUStats(fi)

	return ret
}
