package hr.com.port.ips.eracun.scheduler;

import org.apache.log4j.Logger;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import com.sun.management.OperatingSystemMXBean;
import java.util.concurrent.*;

public final class MemoryWatchdog {
    private static final Logger logger = Logger.getLogger(MemoryWatchdog.class);
    private static final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(r -> {
        Thread t = new Thread(r, "MemoryWatchdog");
        t.setDaemon(true);
        return t;
    });

    private MemoryWatchdog() {}

    public static void start(long periodSeconds) {
        ses.scheduleAtFixedRate(MemoryWatchdog::logSnapshot, 0, periodSeconds, TimeUnit.SECONDS);
    }

    public static void stop() {
        ses.shutdownNow();
    }

    public static void logSnapshot() {
        Runtime rt = Runtime.getRuntime();
        long max = rt.maxMemory();
        long total = rt.totalMemory();
        long free = rt.freeMemory();
        long used = total - free;

        MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heap = mbean.getHeapMemoryUsage();

        OperatingSystemMXBean os = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        long physTotal = os.getTotalPhysicalMemorySize();
        long physFree  = os.getFreePhysicalMemorySize();

        logger.info(String.format(
            "MEM | heapUsed=%s / heapCommitted=%s / heapMax=%s | rtUsed=%s / rtFree=%s / rtMax=%s | RAM free=%s / total=%s",
            human(heap.getUsed()), human(heap.getCommitted()), human(heap.getMax()),
            human(used), human(free), human(max),
            human(physFree), human(physTotal)
        ));
    }

    public static void forceGcAndLog(String reason) {
        logger.info("MEM | System.gc() requested: " + reason);
        System.gc(); // samo za dijagnostiku
        try { Thread.sleep(250); } catch (InterruptedException ignored) {}
        logSnapshot();
    }

    private static String human(long b) {
        if (b < 1024) return b + " B";
        double kb = b / 1024.0;
        if (kb < 1024) return String.format("%.1f KB", kb);
        double mb = kb / 1024.0;
        if (mb < 1024) return String.format("%.1f MB", mb);
        double gb = mb / 1024.0;
        return String.format("%.2f GB", gb);
    }
}
