import java.util.LinkedHashMap;
import java.util.Map;

/** Idempotency: kunci deduplikasi membuat retry aman untuk diulang. */
public class KunciIdempotensi {

    /** Service penagihan rentan: setiap panggilan menagih ulang. */
    static class PenagihanRentan {
        private long totalTagihan = 0;

        String tagih(String pesanan, long jumlah) {
            totalTagihan += jumlah;
            return "menagih " + pesanan + " sebesar Rp" + jumlah
                    + ", total kini Rp" + totalTagihan;
        }
    }

    /** Service penagihan idempotent: hasil pertama disimpan per kunci. */
    static class PenagihanAman {
        private final Map<String, String> hasilPerKunci = new LinkedHashMap<>();
        private long totalTagihan = 0;

        String tagih(String kunci, String pesanan, long jumlah) {
            String tersimpan = hasilPerKunci.get(kunci);
            if (tersimpan != null) {
                return "DUPLIKAT -> " + tersimpan + " (tidak menagih ulang)";
            }
            totalTagihan += jumlah;   // efek samping hanya terjadi sekali per kunci
            String hasil = "menagih " + pesanan + " sebesar Rp" + jumlah
                    + ", total kini Rp" + totalTagihan;
            hasilPerKunci.put(kunci, hasil);
            return hasil;
        }
    }

    public static void main(String[] args) {
        System.out.println("== TANPA kunci idempotensi: retry menagih dua kali ==");
        PenagihanRentan rentan = new PenagihanRentan();
        System.out.println("  percobaan 1 : " + rentan.tagih("pesanan-1001", 250_000));
        System.out.println("  percobaan 2 : " + rentan.tagih("pesanan-1001", 250_000));

        System.out.println();
        System.out.println("== DENGAN kunci idempotensi: retry dikenali ==");
        PenagihanAman aman = new PenagihanAman();
        System.out.println("  percobaan 1 : "
                + aman.tagih("key-abc-1001", "pesanan-1001", 250_000));
        System.out.println("  percobaan 2 : "   // retry karena jawaban pertama hilang
                + aman.tagih("key-abc-1001", "pesanan-1001", 250_000));
        System.out.println("  pesanan lain: "
                + aman.tagih("key-xyz-1002", "pesanan-1002", 175_000));

        System.out.println();
        System.out.println("== Idempotensi alami pada operasi set ==");
        long saldo = 0;
        for (int i = 1; i <= 3; i++) {
            saldo = 500_000;   // setSaldo: hasil akhir tidak bergantung jumlah pemanggilan
            System.out.println("  setSaldo(500000) pemanggilan ke-" + i
                    + " -> saldo = Rp" + saldo);
        }
    }
}
