package util

import (
	"fmt"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/process"
	"os/exec"
	"sort"
	"strconv"
	"strings"
	"time"
)

type ProcessInfo struct {
	Pid      int32   `json:"pid"`
	Name     string  `json:"name"`
	CpuUsage float64 `json:"cpuUsage"`
	MemUsage float32 `json:"memUsage"`
}

func GetTop10CpuAndMem() ([]ProcessInfo, []ProcessInfo) {
	// 获取所有进程的CPU占用率
	processes, err := process.Processes()
	if err != nil {
		//fmt.Println("Error:", err)
		return nil, nil
	}

	// 创建一个用于存储进程CPU占用率的映射
	cpuPercent := make(map[int32]float64)
	memPercent := make(map[int32]float32)

	// 获取每个进程的CPU占用率
	for _, p := range processes {
		pid := p.Pid
		cpuPercent[pid], err = p.CPUPercent()
		memPercent[pid], err = p.MemoryPercent()
	}

	// 根据CPU占用率对进程进行排序
	sortedPidsCpu := make([]int32, 0, len(cpuPercent))
	sortedPidsMem := make([]int32, 0, len(cpuPercent))
	for pid := range cpuPercent {
		sortedPidsCpu = append(sortedPidsCpu, pid)
	}

	sort.Slice(sortedPidsCpu, func(i, j int) bool {
		return cpuPercent[sortedPidsCpu[i]] > cpuPercent[sortedPidsCpu[j]]
	})

	// 输出前10个CPU占用率最高的进程名称
	var top10Cpu []ProcessInfo

	for i, pid := range sortedPidsCpu {
		if i >= 10 {
			break
		}
		p, err := process.NewProcess(pid)
		if err != nil {
			continue
		}
		name, _ := p.Name()
		top10Cpu = append(top10Cpu, ProcessInfo{
			Pid:      pid,
			Name:     name,
			CpuUsage: cpuPercent[pid],
			MemUsage: memPercent[pid],
		})
	}

	// --------------------- 内存
	var top10Mem []ProcessInfo

	for pid := range memPercent {
		sortedPidsMem = append(sortedPidsMem, pid)
	}

	sort.Slice(sortedPidsMem, func(i, j int) bool {
		return memPercent[sortedPidsMem[i]] > memPercent[sortedPidsMem[j]]
	})

	for i, pid := range sortedPidsMem {
		if i >= 10 {
			break
		}
		p, err := process.NewProcess(pid)
		if err != nil {
			continue
		}
		name, _ := p.Name()
		top10Mem = append(top10Mem, ProcessInfo{
			Pid:      pid,
			Name:     name,
			CpuUsage: cpuPercent[pid],
			MemUsage: memPercent[pid],
		})
	}
	return top10Cpu, top10Mem
}

// cpu总占用率
func GetCpuPercent() float64 {
	percent, _ := cpu.Percent(time.Second, false)
	return percent[0]
}

// 内存总占用率
func GetMemoryPercent() float64 {
	memory, _ := mem.VirtualMemory()
	return memory.UsedPercent
}

// 磁盘总占用率
func GetDiskPercent() float64 {
	parts, _ := disk.Partitions(true)
	diskInfo, _ := disk.Usage(parts[0].Mountpoint)
	return diskInfo.UsedPercent
}

// GetDiskUsed 解析 df 命令的输出
// df -B1 /dev/vdb
// Filesystem        1B-blocks        Used    Available Use% Mounted on
// /dev/vdb       527371075584 16390344704 484120408064   4% /mnt/disk001
func GetDiskUsed(filesystem string) (uint64, error) {
	cmd := exec.Command("df", "-B1", filesystem)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return 0, err
	}
	lines := strings.Split(string(output), "\n")
	fields := strings.Fields(lines[1])
	parseUint, err := strconv.ParseUint(fields[2], 10, 64)
	if err != nil {
		return 0, err
	}
	return parseUint, nil
}

// GetDirectoryDiskUsed 获取目录列表的总大小
func GetDirectoryDiskUsed(directories []string) (uint64, error) {
	cmd := exec.Command("du", "-s")
	cmd.Args = append(cmd.Args, directories...)
	output, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Println(err)
		return 0, err
	}
	lines := strings.Split(string(output), "\n")
	sum := uint64(0)
	for _, line := range lines {
		if len(line) > 0 {
			//fmt.Println(line)
			fields := strings.Fields(line)
			parseUint, err := strconv.ParseUint(fields[0], 10, 64)
			//fmt.Println("parseUint", parseUint)
			if err != nil {
				fmt.Println(err)
				return 0, err
			}
			sum += parseUint
		}
	}
	return sum, nil
}

// GetDiskUsagePercent 获取磁盘使用率
func GetDiskUsagePercent() (float64, error) {
	// 执行 df 命令获取磁盘使用情况
	cmd := exec.Command("df", "--total")
	output, err := cmd.Output()
	if err != nil {
		return 0.0, err
	}

	// 解析 df 命令输出,计算磁盘占比
	lines := strings.Split(string(output), "\n")
	for _, line := range lines[1:] {
		fields := strings.Fields(line)
		if len(fields) >= 6 && fields[0] == "total" {
			//filesystem := fields[0]
			total, _ := strconv.ParseFloat(strings.TrimSuffix(fields[1], "G"), 64)
			used, _ := strconv.ParseFloat(strings.TrimSuffix(fields[2], "G"), 64)
			usedPercent := (used / total) * 100

			//fmt.Printf("文件系统 %s 已使用 %.2f%%\n", filesystem, usedPercent)
			return usedPercent, err
		}
	}
	return 0.0, nil
}