package com.mini.capi.utils;


import com.jcraft.jsch.*;
import com.mini.capi.biz.domain.DiskMount;
import com.mini.capi.biz.domain.SysHost;

import java.io.*;
import java.util.*;

public final class HostInfo {


    private static final String HOST_TAG = "c-api";

    public static final class Result {
        public final SysHost host;
        public final List<DiskMount> disks;

        Result(SysHost h, List<DiskMount> d) {
            this.host = h;
            this.disks = d;
        }
    }

    /* ========== 主入口 ========== */
    public static Result collect(String hostIp, int port, String username, String password) throws Exception {

        Session session = null;
        try {
            session = createSession(hostIp, port, username, password);
            SysHost host = collectHost(session);
            List<DiskMount> disks = collectDisk(session);
            return new Result(host, disks);
        } finally {
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    }

    /* ========== SSH 工具 ========== */
    private static Session createSession(String ip, int port, String user, String pwd) throws JSchException {
        JSch jsch = new JSch();
        Session session = jsch.getSession(user, ip, port);
        session.setPassword(pwd);
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect(10_000);
        return session;
    }

    private static String exec(Session session, String cmd) throws Exception {
        ChannelExec ch = (ChannelExec) session.openChannel("exec");
        ch.setCommand(cmd);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayOutputStream err = new ByteArrayOutputStream();
        ch.setOutputStream(out);
        ch.setErrStream(err);
        ch.connect();
        waitForExit(ch);
        ch.disconnect();
        String errStr = err.toString().trim();
        if (!errStr.isEmpty()) {
            throw new RuntimeException("Remote cmd error: " + errStr);
        }
        return out.toString().trim();
    }

    private static void waitForExit(ChannelExec ch) {
        long start = System.currentTimeMillis();
        while (!ch.isClosed()) {
            if (System.currentTimeMillis() - start > 30_000) {
                throw new RuntimeException("Command timeout");
            }
        }
    }

    /* ========== 采集主机信息 ========== */
    private static SysHost collectHost(Session session) throws Exception {
        SysHost host = new SysHost();
        host.setHostTag(HOST_TAG);
        host.setHostname(exec(session, "hostname -s"));
        host.setCpuArch(exec(session, "uname -m"));
        // CPU 型号：取 model name 第一行
        String cpuInfo = exec(session, "cat /proc/cpuinfo | grep 'model name' | head -1");
        host.setCpuModel(cpuInfo.contains(":") ? cpuInfo.split(":", 2)[1].trim() : null);
        // 核心数
        String cores = exec(session, "nproc --all");
        host.setCpuCores(parseInt(cores));
        // CPU 使用率：top -bn1 取 idle 字段
        String top = exec(session, "top -bn1 | grep 'Cpu(s)'");
        host.setCpuUsage(top);
        return host;
    }

    /* ========== 采集磁盘信息 ========== */
    private static List<DiskMount> collectDisk(Session session) throws Exception {
        String df = exec(session, "df -k -P | tail -n +2"); // 去掉标题行
        List<DiskMount> list = new ArrayList<>();
        for (String line : df.split("\n")) {
            String[] arr = line.trim().split("\\s+");
            if (arr.length < 6) continue; // 跳过异常行
            DiskMount d = new DiskMount();
            d.setDiskFs(arr[0]);
            d.setSizeKb(vF.format(Long.parseLong(arr[1])));
            d.setUsedKb(vF.format(Long.parseLong(arr[2])));
            d.setAvailKb(vF.format(Long.parseLong(arr[3])));
            d.setUseRatio(arr[4]);
            d.setMountPoint(arr[5]);
            list.add(d);
        }
        return list;
    }

    /* ========== 工具方法 ========== */
    private static Integer parseInt(String s) {
        try {
            return Integer.parseInt(s.trim());
        } catch (Exception e) {
            return null;
        }
    }
}