package com.mini.capi.utils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

public class HostRuntime {


    /**
     * 统一的数据载体
     */

    public static class Snapshot {
        public String hostName;             // 主机名
        public long timestamp;            // 采集时间戳（毫秒）
        public double cpuUsage;             // CPU 使用率 0~1
        public long memTotal;             // 内存总量（Byte）
        public long memFree;              // 空闲内存（Byte）
        public long memUsed;              // 已用内存（Byte）
        public double memUsage;             // 内存使用率 0~1
        public long swapTotal;            // Swap 总量
        public long swapUsed;             // Swap 已用
        public List<DiskUsage> disks;       // 各挂载点磁盘
        public long netRxBytes;           // 累计接收字节
        public long netTxBytes;           // 累计发送字节
        public double load1;                // 1 分钟平均负载
        public int processCount;         // 进程数
        public long uptimeSec;            // 开机时间（秒）

        @Override
        public String toString() {
            return "Snapshot{" +
                    "hostName='" + hostName + '\'' +
                    ", ts=" + Instant.ofEpochMilli(timestamp) +
                    ", cpu=" + String.format("%.2f", cpuUsage * 100) + "%" +
                    ", mem=" + String.format("%.2f", memUsage * 100) + "%" +
                    ", load=" + load1 +
                    ", uptime=" + uptimeSec + "s}";
        }
    }

    public static class DiskUsage {
        public String path;
        public long total;
        public long free;
        public long used;
        public double usage;

        public DiskUsage(String path, long total, long free, long used, double usage) {
            this.path = path;
            this.total = total;
            this.free = free;
            this.used = used;
            this.usage = usage;
        }
    }

    /**
     * 采集一次主机状态
     */
    public static Snapshot collect() {
        Snapshot s = new Snapshot();
        s.timestamp = System.currentTimeMillis();
        try {
            s.hostName = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            s.hostName = "unknown";
        }

        OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
        s.load1 = os.getSystemLoadAverage();
        s.uptimeSec = getUptimeSec();
        s.processCount = getProcessCount();

        /* ------ CPU ------ */
        s.cpuUsage = getCpuUsage();

        /* ------ Memory ------ */
        long[] mem = getMemInfo();
        s.memTotal = mem[0];
        s.memFree = mem[1];
        s.memUsed = s.memTotal - s.memFree;
        s.memUsage = s.memTotal == 0 ? 0 : (double) s.memUsed / s.memTotal;
        s.swapTotal = mem[2];
        s.swapUsed = mem[3];

        /* ------ Disk ------ */
        s.disks = new ArrayList<>();
        java.io.File[] roots = java.io.File.listRoots();
        for (java.io.File f : roots) {
            long total = f.getTotalSpace();
            long free = f.getFreeSpace();
            long used = total - free;
            double usage = total == 0 ? 0 : (double) used / total;
            s.disks.add(new DiskUsage(f.getPath(), total, free, used, usage));
        }

        /* ------ Network ------ */
        long[] net = getNetInfo();
        s.netRxBytes = net[0];
        s.netTxBytes = net[1];

        return s;
    }

    /* ----------------- 私有工具方法 ----------------- */

    private static double getCpuUsage() {
        // 利用 com.sun.management.OperatingSystemMXBean（JDK 自带）
        com.sun.management.OperatingSystemMXBean sunOs =
                (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        return sunOs.getProcessCpuLoad(); // 进程级
        // 若想系统级：sunOs.getSystemCpuLoad();
    }

    private static long getUptimeSec() {
        // 通过 JVM 启动时间计算
        return ManagementFactory.getRuntimeMXBean().getUptime() / 1000;
    }

    private static int getProcessCount() {
        // 简单实现：线程数，不够精确；若要精确需解析 /proc
        return ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); // 仅作示例
    }

    private static long[] getMemInfo() {
        long total = 0, free = 0, swapTotal = 0, swapUsed = 0;
        try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
            String line;
            while ((line = br.readLine()) != null) {
                if (line.startsWith("MemTotal:")) total = parseMemLine(line);
                if (line.startsWith("MemAvailable:")) free = parseMemLine(line);
                if (line.startsWith("SwapTotal:")) swapTotal = parseMemLine(line);
                if (line.startsWith("SwapFree:")) swapUsed = swapTotal - parseMemLine(line);
            }
        } catch (IOException | NumberFormatException ignore) {
            // fallback to OperatingSystemMXBean
            OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
            if (os instanceof com.sun.management.OperatingSystemMXBean) {
                com.sun.management.OperatingSystemMXBean sunOs =
                        (com.sun.management.OperatingSystemMXBean) os;
                total = sunOs.getTotalMemorySize();
                free = sunOs.getFreeMemorySize();
            }
        }
        return new long[]{total, free, swapTotal, swapUsed};
    }

    private static long parseMemLine(String line) {
        String[] parts = line.split("\\s+");
        return Long.parseLong(parts[1]) * 1024; // kB -> Byte
    }

    private static long[] getNetInfo() {
        // 读取 /proc/net/dev 第一行即可拿到累计字节
        long rx = 0, tx = 0;
        try (BufferedReader br = new BufferedReader(new FileReader("/proc/net/dev"))) {
            br.readLine();
            br.readLine(); // 跳过表头
            String line;
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (line.startsWith("lo:")) continue; // 忽略回环
                String[] parts = line.split("\\s+");
                if (parts.length >= 10) {
                    rx += Long.parseLong(parts[1]);
                    tx += Long.parseLong(parts[9]);
                }
            }
        } catch (IOException | NumberFormatException ignore) {
            // 非 Linux 平台直接返回 0
        }
        return new long[]{rx, tx};
    }
}
