import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/** Registri metrik mini: counter, gauge, histogram + eksposur format Prometheus. */
public class PenaMetrik {

    /** Counter: nilai yang hanya naik — jumlah kejadian sejak aplikasi menyala. */
    static class Counter {
        private double nilai;

        void inc() {
            nilai += 1;
        }

        void inc(double n) {
            nilai += n;
        }

        double nilai() {
            return nilai;
        }
    }

    /** Gauge: nilai yang bisa naik-turun — kondisi saat ini. */
    static class Gauge {
        private double nilai;

        void set(double n) {
            nilai = n;
        }

        double nilai() {
            return nilai;
        }
    }

    /** Histogram: sebaran durasi ke dalam bucket kumulatif. */
    static class Histogram {
        private final double[] batas;
        private final long[] bucket;
        private double jumlah;
        private long cacah;

        Histogram(double[] batas) {
            this.batas = batas;
            this.bucket = new long[batas.length];
        }

        void amati(double nilai) {
            jumlah += nilai;
            cacah++;
            for (int i = 0; i < batas.length; i++) {
                if (nilai <= batas[i]) {
                    bucket[i]++;
                }
            }
        }

        void ekspos(String nama, StringBuilder out) {
            for (int i = 0; i < batas.length; i++) {
                out.append(String.format("%s_bucket{le=\"%s\"} %d%n", nama,
                        (batas[i] >= Double.POSITIVE_INFINITY) ? "+Inf" : batas[i], bucket[i]));
            }
            out.append(String.format("%s_count %d%n", nama, cacah));
            out.append(String.format("%s_sum %s%n", nama, jumlah));
        }
    }

    public static void main(String[] args) {
        Counter pesanan = new Counter();
        pesanan.inc();
        pesanan.inc();
        pesanan.inc(2.0); // dua pesanan sekaligus dari satu pelanggan

        Gauge antrean = new Gauge();
        antrean.set(7);

        Histogram latensi = new Histogram(new double[]{0.1, 0.5, 1.0, Double.POSITIVE_INFINITY});
        for (double d : List.of(0.08, 0.12, 0.34, 0.41, 0.9, 1.4)) {
            latensi.amati(d);
        }

        System.out.println("== Nilai internal registri ==");
        System.out.printf("pesanan_dibuat_total = %.0f%n", pesanan.nilai());
        System.out.printf("antrean_pesanan      = %.0f%n", antrean.nilai());
        System.out.println();

        System.out.println("== Eksposur GET /metrics (format teks Prometheus, tanpa baris komentar) ==");
        StringBuilder out = new StringBuilder();
        out.append(String.format("pesanan_dibuat_total %.0f%n", pesanan.nilai()));
        out.append(String.format("antrean_pesanan %.0f%n", antrean.nilai()));
        latensi.ekspos("latensi_pesanan_seconds", out);
        System.out.print(out);

        System.out.println();
        Map<String, Double> contohJvm = new TreeMap<>();
        contohJvm.put("jvm_memory_used_bytes{area=\"heap\"}", 268435456.0);
        contohJvm.put("jvm_memory_used_bytes{area=\"nonheap\"}", 71303168.0);
        System.out.println("== Metrik JVM yang ikut terekspos otomatis (contoh) ==");
        for (var e : contohJvm.entrySet()) {
            System.out.printf("%s %.0f%n", e.getKey(), e.getValue());
        }
    }
}
