package net.halbear.Terrain4J.EngineCore.Profiling;

import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import org.tinylog.Logger;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class CPUMonitor {
    private final OperatingSystemMXBean OSBean;
    public static String RamSize = "0.0GB";

    public CPUMonitor(){
        OSBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
    }

    public static String GetRamSize(){return RamSize;}

    public static String[] LogCPUUsage(){
        OperatingSystemMXBean OSBean= (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        double processCPU = OSBean.getProcessCpuLoad();
        double SystemCPU = OSBean.getCpuLoad();
        long totalPhysicalMemory = OSBean.getTotalPhysicalMemorySize();
        long freePhysicalMemory = OSBean.getFreePhysicalMemorySize();
        long usedPhysicalMemory = totalPhysicalMemory - freePhysicalMemory;

        RamSize = String.format("%.2f" + "gb",ConvertToGB(totalPhysicalMemory));

        Runtime runtime = Runtime.getRuntime();
        long maxHeap = runtime.maxMemory();
        long totalHeap = runtime.totalMemory();
        long freeHeap = runtime.freeMemory();
        long usedHeap = totalHeap - freeHeap;
        int TotalCores = Runtime.getRuntime().availableProcessors();
        double ActiveSystemCores = TotalCores * SystemCPU;
        double ActiveProcessCores = TotalCores * processCPU;
        String[] CPUMetrics = new String[6];
        CPUMetrics[0] = String.format("CPU & SYSTEM MEMORY USAGE:\n");
        CPUMetrics[1] = String.format("  Terrain4J CPU Core Usage: %d / %d", (int)Math.ceil(ActiveProcessCores),TotalCores);
        CPUMetrics[2] = String.format("  Terrain4J CPU Usage: %.2f%%%n", processCPU * 100);
        CPUMetrics[3] = String.format("  Terrain4J Memory Usage: %d MB / %d MB%n", ConvertToMB(usedHeap), ConvertToMB(maxHeap));
        CPUMetrics[4] = String.format("  Total CPU Load: %.2f%%%n", SystemCPU * 100);
        CPUMetrics[5] = String.format("  System Memory Used: %d MB / %d MB%n", ConvertToMB(usedPhysicalMemory), ConvertToMB(totalPhysicalMemory));
        return CPUMetrics;
    }

    public static List<String> GetThreadsInUse(){
        List<String> Threads = new ArrayList<>();
        Thread.getAllStackTraces().keySet().forEach(thread ->
        {
            Threads.add(thread.getName());
        });
        return Threads;
    }

    private static double ConvertToGB(long bytes) {
        return (double)(bytes / (1024 * 1024* 1024));
    }
    private static long ConvertToMB(long bytes) {
        return bytes / (1024 * 1024);
    }
    public static int getCoreCount(){
        return Runtime.getRuntime().availableProcessors();
    }
    public static String getCpuName() {
        String os = System.getProperty("os.name").toLowerCase();
        String command = "";

        if (os.contains("win")) {
            command = "wmic cpu get name";
        } else if (os.contains("mac")) {
            command = "sysctl -n machdep.cpu.brand_string";
        } else if (os.contains("nix") || os.contains("nux") || os.contains("aix")) {
            command = "sh -c lscpu | grep 'Model name:'";
        } else {
            return "Unknown OS - Cannot fetch CPU name";
        }

        try {
            Process process = Runtime.getRuntime().exec(command);
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                StringBuilder output = new StringBuilder();

                while ((line = reader.readLine()) != null) {
                    if (!line.trim().isEmpty() && !line.toLowerCase().contains("name")) {
                        output.append(line.trim());
                        break;
                    }
                }
                return output.toString().isEmpty() ? "Unknown CPU" : output.toString();
            }
        } catch (Exception e) {
            return "Error reading CPU name: " + e.getMessage();
        }
    }
}
