import java.io.StringReader;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;

/** Konfigurasi berlapis: default di dalam kode < berkas eksternal < environment variable. */
public class LapisKonfigurasi {

    /** Lapis 1: default yang aman untuk pengembangan. */
    static final Map<String, String> DEFAULT = Map.of(
            "app.name", "aplikasi-kasir",
            "app.env", "dev",
            "app.database.url", "jdbc:sqlite:data/kasir-dev.db",
            "app.database.driver", "org.postgresql.Driver",
            "app.log.level", "DEBUG",
            "app.pool.max", "5");

    /** Lapis 2: isi config/application.properties yang diletakkan operator
     *  di sebelah JAR — pada program ini disematkan sebagai string agar mandiri. */
    static final String ISI_BERKAS = """
            app.database.url=jdbc:postgresql://db.internal:5432/kasir
            app.log.level=INFO
            app.pool.max=10
            """;

    /** Lapis 3: environment variable proses. Argumen program dengan format
     *  KUNCI=nilai menyimulasikan env var agar demo bisa dijalankan tanpa
     *  menyetel lingkungan sungguhan; System.getenv tetap diperiksa. */
    static Map<String, String> envSimulasi = new LinkedHashMap<>();

    /** Pemetaan binding longgar: app.pool.max -> APP_POOL_MAX. */
    static String bacaEnv(String kunciKonfigurasi) {
        String namaVar = kunciKonfigurasi.toUpperCase().replace('.', '_');
        if (envSimulasi.containsKey(namaVar)) {
            return envSimulasi.get(namaVar);
        }
        return System.getenv(namaVar);
    }

    public static void main(String[] args) throws Exception {
        for (String a : args) {
            int pos = a.indexOf('=');
            if (pos > 0) {
                envSimulasi.put(a.substring(0, pos), a.substring(pos + 1));
            }
        }

        Properties berkas = new Properties();
        berkas.load(new StringReader(ISI_BERKAS));

        System.out.println("== Lapisan sumber (urutan prioritas menaik) ==");
        System.out.println("1. default di dalam kode : " + DEFAULT.size() + " kunci");
        System.out.println("2. berkas eksternal      : " + berkas.size() + " kunci");
        System.out.println("3. environment variable  : " + envSimulasi + " (disimulasikan lewat argumen)");
        System.out.println();

        System.out.println("== Tabel konfigurasi gabungan ==");
        TreeMap<String, String[]> gabungan = new TreeMap<>(); // kunci -> {nilai, sumber}
        for (var e : DEFAULT.entrySet()) {
            gabungan.put(e.getKey(), new String[]{e.getValue(), "default"});
        }
        for (var e : berkas.entrySet()) {
            gabungan.put((String) e.getKey(), new String[]{(String) e.getValue(), "berkas"});
        }
        int dariEnv = 0, tertimpaBerkas = 0;
        for (String kunci : gabungan.keySet()) {
            String nilaiEnv = bacaEnv(kunci);
            if (nilaiEnv != null) {
                if (gabungan.get(kunci)[1].equals("berkas")) {
                    tertimpaBerkas++;
                }
                gabungan.put(kunci, new String[]{nilaiEnv, "env"});
                dariEnv++;
            }
        }
        for (var e : gabungan.entrySet()) {
            String[] v = e.getValue();
            System.out.printf("  %-22s = %-45s [%s]%n", e.getKey(), v[0], v[1]);
        }
        System.out.println();
        System.out.println("kunci dari env            : " + dariEnv);
        System.out.println("menimpa nilai dari berkas : " + tertimpaBerkas);
    }
}
