import java.util.ArrayList;
import java.util.List;

/** Transaksi lintas service: bahaya komit lokal, lalu two-phase commit (2PC) mini. */
public class TransaksiLintasService {

    /** Satu service peserta dengan perubahan dua tahap: siapkan lalu kommit/batalkan. */
    static class Peserta {
        private final String nama;
        private String tersiap = null;  // perubahan tahap PREPARE (belum menempel)
        private String menempel = null; // hasil kommit terakhir

        Peserta(String nama) {
            this.nama = nama;
        }

        /** Fase 1: peserta menyiapkan perubahan dan memberi suara. */
        boolean siapkan(String perubahan, boolean setuju) {
            if (!setuju) {
                tersiap = null;
                return false;
            }
            tersiap = perubahan;
            return true;
        }

        /** Fase 2a: kommit menempelkan perubahan yang disiapkan. */
        void kommit() {
            menempel = tersiap;
            tersiap = null;
        }

        /** Fase 2b: abort membuang perubahan yang disiapkan. */
        void batalkan() {
            tersiap = null;
        }

        String status() {
            return nama + ": menempel=" + menempel
                    + (tersiap != null ? ", tersiap=" + tersiap : "");
        }
    }

    public static void main(String[] args) {
        System.out.println("== MASALAH: komit lokal langkah demi langkah ==");
        komitLokal();

        System.out.println();
        System.out.println("== 2PC: semua setuju -> kommit bersama ==");
        duaFase(true);

        System.out.println();
        System.out.println("== 2PC: satu menolak -> abort bersama ==");
        duaFase(false);
    }

    /** Tanpa koordinator: langkah pertama menempel, langkah kedua gagal di tengah. */
    static void komitLokal() {
        List<String> jejak = new ArrayList<>();
        jejak.add("svc-penerbangan kommit : kursi 12A dipesan untuk Budi");
        jejak.add("svc-tagihan gagal       : kartu ditolak, tidak ada yang dikommit");
        jejak.add("keadaan akhir           : kursi 12A terpakai tanpa pembayaran");
        jejak.add("kesimpulan              : atomisitas tidak melintasi proses");
        for (String j : jejak) {
            System.out.println("  " + j);
        }
    }

    /** Two-phase commit terhadap dua peserta. */
    static void duaFase(boolean pembayaranSetuju) {
        Peserta penerbangan = new Peserta("svc-penerbangan");
        Peserta tagihan = new Peserta("svc-tagihan");

        // FASE 1 (PREPARE): koordinator mengumpulkan suara semua peserta
        boolean suaraTerbang = penerbangan.siapkan("kursi 12A untuk Budi", true);
        boolean suaraBayar = tagihan.siapkan("tagih Rp1200000", pembayaranSetuju);
        System.out.println("  fase 1 (prepare): penerbangan=" + suaraTerbang
                + ", tagihan=" + suaraBayar);

        // FASE 2 (COMMIT/ABORT): satu keputusan untuk semua peserta
        if (suaraTerbang && suaraBayar) {
            penerbangan.kommit();
            tagihan.kommit();
            System.out.println("  fase 2 (commit) : kedua perubahan menempel bersama");
        } else {
            penerbangan.batalkan();
            tagihan.batalkan();
            System.out.println("  fase 2 (abort)  : kedua perubahan dibatalkan bersama");
        }
        System.out.println("  " + penerbangan.status());
        System.out.println("  " + tagihan.status());
    }
}
