package service

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	"nms_nbi/src/framework/config"
	"nms_nbi/src/framework/utils/parse"

	"github.com/shirou/gopsutil/v3/cpu"
	"github.com/shirou/gopsutil/v3/disk"
	"github.com/shirou/gopsutil/v3/host"
	"github.com/shirou/gopsutil/v3/mem"
	"github.com/shirou/gopsutil/v3/net"
)

// 实例化服务层 SystemInfoImpl 结构体
var NewSystemInfoImpl = &SystemInfoImpl{}

// SystemInfoImpl 服务器系统相关信息 服务层处理
type SystemInfoImpl struct{}

// SystemInfo 系统信息
func (s *SystemInfoImpl) SystemInfo() map[string]any {
	info, err := host.Info()
	if err != nil {
		info.Platform = err.Error()
	}
	// 获取主机运行时间
	bootTime := time.Since(time.Unix(int64(info.BootTime), 0)).Seconds()
	// 获取程序运行时间
	runTime := time.Since(config.RunTime()).Abs().Seconds()
	return map[string]any{
		"platform":        info.Platform,
		"platformVersion": info.PlatformVersion,
		"arch":            info.KernelArch,
		"archVersion":     info.KernelVersion,
		"os":              info.OS,
		"hostname":        info.Hostname,
		"bootTime":        int64(bootTime),
		"processId":       os.Getpid(),
		"runArch":         runtime.GOARCH,
		"runVersion":      runtime.Version(),
		"runTime":         int64(runTime),
	}
}

// TimeInfo 系统时间信息
func (s *SystemInfoImpl) TimeInfo() map[string]string {
	now := time.Now()
	// 获取当前时间
	current := now.Format("2006-01-02 15:04:05")
	// 获取时区
	timezone := now.Format("-0700 MST")
	// 获取时区名称
	timezoneName := now.Format("MST")

	return map[string]string{
		"current":      current,
		"timezone":     timezone,
		"timezoneName": timezoneName,
	}
}

// MemoryInfo 内存信息
func (s *SystemInfoImpl) MemoryInfo() map[string]any {
	memInfo, err := mem.VirtualMemory()
	if err != nil {
		memInfo.UsedPercent = 0
		memInfo.Available = 0
		memInfo.Total = 0
	}

	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)

	return map[string]any{
		"usage":     fmt.Sprintf("%.2f", memInfo.UsedPercent),            // 内存利用率
		"freemem":   parse.Bit(float64(memInfo.Available)),               // 可用内存大小（GB）
		"totalmem":  parse.Bit(float64(memInfo.Total)),                   // 总内存大小（GB）
		"rss":       parse.Bit(float64(memStats.Sys)),                    // 常驻内存大小（RSS）
		"heapTotal": parse.Bit(float64(memStats.HeapSys)),                // 堆总大小
		"heapUsed":  parse.Bit(float64(memStats.HeapAlloc)),              // 堆已使用大小
		"external":  parse.Bit(float64(memStats.Sys - memStats.HeapSys)), // 外部内存大小（非堆）
	}
}

// CPUInfo CPU信息
func (s *SystemInfoImpl) CPUInfo() map[string]any {
	var core int = 0
	var speed string = "未知"
	var model string = "未知"
	cpuInfo, err := cpu.Info()
	if err == nil {
		core = runtime.NumCPU()
		speed = fmt.Sprintf("%.0fMHz", cpuInfo[0].Mhz)
		model = strings.TrimSpace(cpuInfo[0].ModelName)
	}

	useds := []string{}
	cpuPercent, err := cpu.Percent(0, true)
	if err == nil {
		for _, v := range cpuPercent {
			useds = append(useds, fmt.Sprintf("%.2f", v))
		}
	}

	return map[string]any{
		"model":    model,
		"speed":    speed,
		"core":     core,
		"coreUsed": useds,
	}
}

// NetworkInfo 网络信息
func (s *SystemInfoImpl) NetworkInfo() map[string]string {
	ipAddrs := make(map[string]string)
	interfaces, err := net.Interfaces()
	if err == nil {
		for _, iface := range interfaces {
			name := iface.Name
			if name[len(name)-1] == '0' {
				name = name[0 : len(name)-1]
				name = strings.Trim(name, "")
			}
			// ignore localhost
			if name == "lo" {
				continue
			}
			var addrs []string
			for _, v := range iface.Addrs {
				prefix := strings.Split(v.Addr, "/")[0]
				if strings.Contains(prefix, "::") {
					addrs = append(addrs, fmt.Sprintf("IPv6 %s", prefix))
				}
				if strings.Contains(prefix, ".") {
					addrs = append(addrs, fmt.Sprintf("IPv4 %s", prefix))
				}
			}
			ipAddrs[name] = strings.Join(addrs, " / ")
		}
	}
	return ipAddrs
}

// DiskInfo 磁盘信息
func (s *SystemInfoImpl) DiskInfo() []map[string]string {
	disks := make([]map[string]string, 0)

	partitions, err := disk.Partitions(false)
	if err != nil {
		return disks
	}

	for _, partition := range partitions {
		usage, err := disk.Usage(partition.Mountpoint)
		if err != nil {
			continue
		}
		disks = append(disks, map[string]string{
			"size":   parse.Bit(float64(usage.Total)),
			"used":   parse.Bit(float64(usage.Used)),
			"avail":  parse.Bit(float64(usage.Free)),
			"pcent":  fmt.Sprintf("%.1f%%", usage.UsedPercent),
			"target": partition.Device,
		})
	}
	return disks
}
