//go:build darwin && !cgo
// +build darwin,!cgo

package mem

import (
	"context"
	"strconv"
	"strings"

	"golang.org/x/sys/unix"
)

// Runs vm_stat and returns Free and inactive pages
func getVMStat(vms *VirtualMemoryStat) error {
	out, err := invoke.Command("vm_stat")
	if err != nil {
		return err
	}
	return parseVMStat(string(out), vms)
}

func parseVMStat(out string, vms *VirtualMemoryStat) error {
	var err error

	lines := strings.Split(out, "\n")
	pagesize := uint64(unix.Getpagesize())
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) < 2 {
			continue
		}
		key := strings.TrimSpace(fields[0])
		value := strings.Trim(fields[1], " .")
		switch key {
		case "Pages free":
			free, e := strconv.ParseUint(value, 10, 64)
			if e != nil {
				err = e
			}
			vms.Free = free * pagesize
		case "Pages inactive":
			inactive, e := strconv.ParseUint(value, 10, 64)
			if e != nil {
				err = e
			}
			vms.Inactive = inactive * pagesize
		case "Pages active":
			active, e := strconv.ParseUint(value, 10, 64)
			if e != nil {
				err = e
			}
			vms.Active = active * pagesize
		case "Pages wired down":
			wired, e := strconv.ParseUint(value, 10, 64)
			if e != nil {
				err = e
			}
			vms.Wired = wired * pagesize
		}
	}
	return err
}

// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
	return VirtualMemoryWithContext(context.Background())
}

func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
	ret := &VirtualMemoryStat{}

	total, err := getHwMemsize()
	if err != nil {
		return nil, err
	}
	err = getVMStat(ret)
	if err != nil {
		return nil, err
	}

	ret.Available = ret.Free + ret.Inactive
	ret.Total = total

	ret.Used = ret.Total - ret.Available
	ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total)

	return ret, nil
}
