package main

import (
	"bufio"
	"os"
	"sort"
	"strconv"
	"strings"
)

// readMemory 读取内存信息
func readMemory() (MemoryMetrics, error) {
	totals := map[string]uint64{}
	f, err := os.Open("/proc/meminfo")
	if err != nil {
		return MemoryMetrics{}, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.Split(line, ":")
		if len(parts) < 2 {
			continue
		}
		key := strings.TrimSpace(parts[0])
		fields := strings.Fields(strings.TrimSpace(parts[1]))
		if len(fields) == 0 {
			continue
		}
		value, err := strconv.ParseUint(fields[0], 10, 64)
		if err != nil {
			continue
		}
		totals[key] = value * 1024 // kB to bytes
	}
	total := totals["MemTotal"]

	// 优先使用 MemAvailable（Linux 3.14+），如果没有则计算
	var free uint64
	if available, ok := totals["MemAvailable"]; ok && available > 0 {
		free = available
	} else {
		// 回退到 MemFree + Buffers + Cached（适用于较老的系统）
		free = totals["MemFree"]
		if buffers, ok := totals["Buffers"]; ok {
			free += buffers
		}
		if cached, ok := totals["Cached"]; ok {
			free += cached
		}
	}

	used := total - free
	usedPercent := 0.0
	if total > 0 {
		usedPercent = (float64(used) / float64(total)) * 100
	}

	swapTotal := totals["SwapTotal"]
	swapFree := totals["SwapFree"]
	swapUsed := uint64(0)
	if swapTotal >= swapFree {
		swapUsed = swapTotal - swapFree
	}
	swapUsedPct := 0.0
	if swapTotal > 0 {
		swapUsedPct = (float64(swapUsed) / float64(swapTotal)) * 100
	}
	swapType := summarizeSwapTypes(swapTotal)

	return MemoryMetrics{
		TotalBytes:      total,
		UsedBytes:       used,
		FreeBytes:       free,
		UsedPercent:     round(usedPercent, 2),
		SwapTotalBytes:  swapTotal,
		SwapUsedBytes:   swapUsed,
		SwapFreeBytes:   swapFree,
		SwapUsedPercent: round(swapUsedPct, 2),
		SwapType:        swapType,
	}, nil
}

// summarizeSwapTypes 根据 /proc/swaps 汇总交换区类型（file / partition / zram 等）；无 swap 时为「无」
func summarizeSwapTypes(swapTotalFromMeminfo uint64) string {
	if swapTotalFromMeminfo == 0 {
		return "无"
	}
	f, err := os.Open("/proc/swaps")
	if err != nil {
		return "未知"
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	lineNum := 0
	seen := map[string]struct{}{}
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		lineNum++
		if lineNum == 1 || line == "" {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) < 2 {
			continue
		}
		filename := fields[0]
		typ := fields[1]
		if strings.Contains(strings.ToLower(filename), "zram") {
			typ = "zram"
		}
		seen[typ] = struct{}{}
	}
	if len(seen) == 0 {
		if swapTotalFromMeminfo > 0 {
			return "未知"
		}
		return "无"
	}
	list := make([]string, 0, len(seen))
	for t := range seen {
		list = append(list, t)
	}
	sort.Strings(list)
	return strings.Join(list, " + ")
}
