package com.emoon.chat.service.impl;

import com.emoon.chat.service.IHardwareInfoService;
import com.emoon.chat.utils.HttpUtils;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import org.springframework.beans.factory.annotation.Value;

import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
@Service
public class HardwareInfoServiceImpl implements IHardwareInfoService {

    private final SystemInfo systemInfo = new SystemInfo();
    private final HardwareAbstractionLayer hal = systemInfo.getHardware();
    private final ObjectMapper objectMapper = new ObjectMapper();
    private long[] prevTicks = null;
    @Value("${enflame.url}")
    private String enflameApiUrl;

    /**
     * 获取本机硬件 + 集群节点信息（Supervisor + 多个 Worker）
     */
    @Override
    public HardwareData getHardwareData() {
        CentralProcessor processor = hal.getProcessor();
        GlobalMemory memory = hal.getMemory();

        // 1. 本机 CPU 使用率
        double cpuUsage = getCpuLoad(processor);

        // 2. 本机内存
        long totalMemory = memory.getTotal();
        long availableMemory = memory.getAvailable();


        // 3. 磁盘信息
        List<DiskData> disks = systemInfo.getOperatingSystem().getFileSystem().getFileStores().stream()
            .map(store -> new DiskData(
                store.getMount(),
                store.getTotalSpace(),
                store.getUsableSpace()))
            .collect(Collectors.toList());

        // 4. 网络信息
        List<NetworkData> networks = hal.getNetworkIFs().stream()
            .filter(net -> net.getBytesRecv() > 0 || net.getBytesSent() > 0) // 可选：过滤无流量的网卡
            .map(net -> new NetworkData(
                net.getName(),
                net.getBytesRecv(),
                net.getBytesSent()))
            .collect(Collectors.toList());

        // 5. 获取集群节点信息
        ClusterNodes clusterNodes = getClusterNodes();

        // 6. 返回合并数据
        return new HardwareData(cpuUsage, totalMemory, availableMemory, disks, networks,
            clusterNodes.getSupervisor(), clusterNodes.getWorkers());
    }

    /**
     * 计算 CPU 使用率（两次采样之间）
     */
    private double getCpuLoad(CentralProcessor processor) {
        if (prevTicks == null) {
            prevTicks = processor.getSystemCpuLoadTicks();
            return 0.0;
        }
        long[] ticks = processor.getSystemCpuLoadTicks();
        double load = processor.getSystemCpuLoadBetweenTicks(prevTicks);
        prevTicks = ticks;
        return Math.round(load * 10000) / 100.0; // 保留两位小数
    }

    /**
     * 从燧原集群 API 获取所有节点信息（Supervisor + Worker）
     */
    private ClusterNodes getClusterNodes() {
        String url = enflameApiUrl + "/v1/cluster/info?detailed=true";
        try {
            String jsonResponse = HttpUtils.sendHttpGet(url);
            if (jsonResponse == null || jsonResponse.trim().isEmpty()) {
                System.err.println("API 返回为空或连接失败: " + url);
                return new ClusterNodes(null, List.of());
            }

            // 解析为 ClusterNodeInfo 列表
            List<ClusterNodeInfo> nodes = objectMapper.readValue(jsonResponse, new TypeReference<List<ClusterNodeInfo>>() {});

            // 分离 Supervisor 和 Worker 节点
            ClusterNodeInfo supervisor = nodes.stream()
                .filter(node -> "Supervisor".equals(node.getNodeType()))
                .findFirst()
                .orElse(null);

            List<ClusterNodeInfo> workers = nodes.stream()
                .filter(node -> "Worker".equals(node.getNodeType()))
                .collect(Collectors.toList());

            return new ClusterNodes(supervisor, workers);

        } catch (Exception e) {
            System.err.println("请求或解析集群信息失败: " + e.getMessage());
            e.printStackTrace();
            return new ClusterNodes(null, List.of()); // 前端可据此显示"集群离线"或"加载中"
        }
    }

    /**
     * 集群节点容器类（用于分组 Supervisor 和 Worker）
     */
    @Data
    private static class ClusterNodes {
        private ClusterNodeInfo supervisor;
        private List<ClusterNodeInfo> workers;

        public ClusterNodes(ClusterNodeInfo supervisor, List<ClusterNodeInfo> workers) {
            this.supervisor = supervisor;
            this.workers = workers;
        }
    }

    // ==================== DTO 数据传输对象 ====================

    @Data
    public static class HardwareData {
        private double cpuUsage; // 本机 CPU 使用率 (%)
        private long totalMemory; // 本机总内存 (bytes)
        private long availableMemory; // 本机可用内存 (bytes)
        private List<DiskData> disks;
        private List<NetworkData> networks;
        private ClusterNodeInfo supervisorNode; // 集群 Supervisor 节点信息
        private List<ClusterNodeInfo> workerNodes; // 集群 Worker 节点列表

        public HardwareData(double cpuUsage, long totalMemory, long availableMemory,
                            List<DiskData> disks, List<NetworkData> networks,
                            ClusterNodeInfo supervisorNode, List<ClusterNodeInfo> workerNodes) {
            this.cpuUsage = cpuUsage;
            this.totalMemory = totalMemory;
            this.availableMemory = availableMemory;
            this.disks = disks;
            this.networks = networks;
            this.supervisorNode = supervisorNode;
            this.workerNodes = workerNodes;
        }
    }

    @Data
    public static class DiskData {
        private String mountPoint;
        private long totalSpace;
        private long usableSpace;

        public DiskData(String mountPoint, long totalSpace, long usableSpace) {
            this.mountPoint = mountPoint;
            this.totalSpace = totalSpace;
            this.usableSpace = usableSpace;
        }
    }

    @Data
    public static class NetworkData {
        private String name;
        private long bytesReceived;
        private long bytesSent;

        public NetworkData(String name, long bytesReceived, long bytesSent) {
            this.name = name;
            this.bytesReceived = bytesReceived;
            this.bytesSent = bytesSent;
        }
    }

    @Data
    public static class ClusterNodeInfo {
        @JsonProperty("node_type")
        private String nodeType;

        @JsonProperty("ip_address")
        private String ipAddress;

        @JsonProperty("gpu_count")
        private Integer gpuCount;

        @JsonProperty("gpu_vram_total")
        private Long gpuVramTotal;

        @JsonProperty("gpu_vram_available")
        private Long gpuVramAvailable;

        @JsonProperty("cpu_available")
        private Double cpuAvailable;

        @JsonProperty("cpu_count")
        private Integer cpuCount;

        @JsonProperty("mem_used")
        private Long memUsed;

        @JsonProperty("mem_available")
        private Long memAvailable;

        @JsonProperty("mem_total")
        private Long memTotal;
    }
}
