import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureRantai {
    public static void main(String[] args) {
        // Executor kustom: tahapan berat tidak menumpuk di common pool.
        ExecutorService eksekutor = Executors.newFixedThreadPool(3);
        try {
            // Rantai 1: ambil total item, gandakan, format menjadi teks.
            // thenApply menjalankan tahap berikutnya TANPA memblokir pemanggil.
            CompletableFuture<String> laporan = CompletableFuture
                    .supplyAsync(() -> 250, eksekutor)
                    .thenApply(total -> total * 2)
                    .thenApply(jumlah -> "total: " + jumlah + " item");

            // Rantai 2: berjalan paralel dengan rantai 1.
            CompletableFuture<String> pelanggan = CompletableFuture
                    .supplyAsync(() -> "Siti", eksekutor)
                    .thenApply(nama -> "pelanggan: " + nama);

            // Kombinasi hasil dua rantai menjadi satu keluaran.
            CompletableFuture<String> gabungan = laporan.thenCombine(
                    pelanggan, (bagianLaporan, bagianPelanggan) ->
                            bagianPelanggan + ", " + bagianLaporan);

            // Rantai dengan pemulihan galat: sumber diskon sengaja melempar
            // exception; exceptionally menyediakan nilai cadangan.
            CompletableFuture<Integer> diskon = CompletableFuture
                    .<Integer>supplyAsync(() -> {
                        throw new IllegalStateException("promosi tidak aktif");
                    }, eksekutor)
                    .exceptionally(e -> 0);

            // Tunggu seluruh rantai tuntas, lalu cetak hasil terurut.
            CompletableFuture.allOf(gabungan, diskon).join();
            System.out.println(gabungan.join());
            System.out.println("diskon terpakai: " + diskon.join() + "%");
        } finally {
            eksekutor.shutdown();
        }
    }
}
