package com.codvision.monitor.entity.server;


import cn.hutool.core.net.NetUtil;
import cn.hutool.system.oshi.CpuInfo;
import cn.hutool.system.oshi.OshiUtil;
import com.codvision.monitor.support.Arith;
import lombok.Data;
import org.apache.commons.io.FileUtils;
import oshi.SystemInfo;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;

import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import static com.codvision.monitor.support.MonitorConstant.LINUX;


/**
 * 服务器相关信息
 *
 * @author hxl
 */
@Data
public class ServerInfo {

    private CpuInfo cpu;
    private Mem mem;
    private Jvm jvm;
    private Sys sys;
    private List<SysFile> sysFiles;
    private DirectoryFile directoryFile;

    private static final OperatingSystem OS;
    private static final SystemInfo SYSTEM_INFO;
    private static final HardwareAbstractionLayer HARDWARE;

    static {
        SYSTEM_INFO = new SystemInfo();
        HARDWARE = SYSTEM_INFO.getHardware();
        OS = SYSTEM_INFO.getOperatingSystem();
    }

    public ServerInfo() {
        init();
    }

    private void init() {
        // 初始化CPU信息
        cpu = OshiUtil.getCpuInfo();
        // 初始化内存信息
        initMemInfo();
        // 初始化服务器信息
        initSysInfo();
        // 初始化JVM信息
        initJvmInfo();
        // 初始化磁盘信息
        initDiskInfo();
        // 初始化data目录
        initDataDirectory();
    }

    private void initMemInfo() {
        GlobalMemory memory = HARDWARE.getMemory();
        mem = Mem.builder().total(memory.getTotal()).free(memory.getAvailable()).used(memory.getTotal() - memory.getAvailable()).build();
    }

    private void initSysInfo() {
        Properties props = System.getProperties();
        sys = Sys.builder().computerName(getHostName()).computerIp(NetUtil.getLocalhostStr())
                .osName(OS.getFamily() + " " + OS.getVersionInfo().getVersion())
                .osArch(props.getProperty("os.arch")).userDir(props.getProperty("user.dir"))
                .build();
    }

    private void initJvmInfo() {
        Properties props = System.getProperties();
        jvm = Jvm.builder().total(Runtime.getRuntime().totalMemory()).max(Runtime.getRuntime().maxMemory())
                .free(Runtime.getRuntime().freeMemory()).version(props.getProperty("java.version")).home(props.getProperty("java.home"))
                .build();
    }

    private void initDiskInfo() {
        sysFiles = new LinkedList<>();
        FileSystem fileSystem = OS.getFileSystem();
        List<OSFileStore> fsArray = fileSystem.getFileStores();
        for (OSFileStore fs : fsArray) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            SysFile sysFile = SysFile.builder().dirName(fs.getMount()).sysTypeName(fs.getType()).typeName(fs.getName())
                    .total(convertFileSize(total)).free(convertFileSize(free)).used(convertFileSize(used)).usage(Arith.mul(Arith.div(used, total, 4), 100)).build();
            sysFiles.add(sysFile);
        }
    }

    private void initDataDirectory() {
        if (LINUX.equalsIgnoreCase(OS.getFamily())) {
            File file = new File("/data");
            if (file.exists()) {
                long total = file.getTotalSpace();
                long free = file.getFreeSpace();
                long used = FileUtils.sizeOfDirectory(file);
                directoryFile = DirectoryFile.builder().total(convertFileSize(total)).free(convertFileSize(free))
                        .used(convertFileSize(used)).usage(Arith.mul(Arith.div(used, total, 4), 100)).build();
            }
        }
    }

    private String convertFileSize(long size) {
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb) {
            return String.format("%.1f GB", (float) size / gb);
        } else if (size >= mb) {
            float f = (float) size / mb;
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
        } else if (size >= kb) {
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
        } else {
            return String.format("%d B", size);
        }
    }

    private String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException ignored) {
        }
        return "未知";
    }
}


