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

public class ContohVerifikasiInteraksi {

    record HasilBayar(boolean sukses, String kode) {}

    interface GatewayPembayaran {
        HasilBayar bayar(String idPesanan, long jumlah);
    }

    // ---- padanan mock(): merekam semua panggilan, jawaban dapat dipasang ----

    static final class FakePembayaran implements GatewayPembayaran {

        record Panggilan(String idPesanan, long jumlah) {}

        private final List<Panggilan> rekaman = new ArrayList<>();
        private HasilBayar jawabanBerikutnya = new HasilBayar(true, "OK");

        void jawabDengan(HasilBayar hasil) {
            this.jawabanBerikutnya = hasil;
        }

        @Override
        public HasilBayar bayar(String idPesanan, long jumlah) {
            rekaman.add(new Panggilan(idPesanan, jumlah));
            return jawabanBerikutnya;
        }

        // padanan verify(gateway).bayar(id, ...)

        boolean pernahMemanggil(String idPesanan) {
            return rekaman.stream().anyMatch(p -> p.idPesanan().equals(idPesanan));
        }

        // padanan ArgumentCaptor: ambil ulang argumen yang diteruskan

        long jumlahUntuk(String idPesanan) {
            return rekaman.stream()
                .filter(p -> p.idPesanan().equals(idPesanan))
                .findFirst()
                .map(Panggilan::jumlah)
                .orElse(-1L);
        }

        int totalPanggilan() {
            return rekaman.size();
        }
    }

    record Pesanan(String id, long total) {}

    static final class Kasir {

        private final GatewayPembayaran pembayaran;

        Kasir(GatewayPembayaran pembayaran) {
            this.pembayaran = pembayaran;
        }

        String proses(Pesanan pesanan) {
            HasilBayar hasil = pembayaran.bayar(pesanan.id(), pesanan.total());
            if (!hasil.sukses()) {
                throw new IllegalStateException("pembayaran ditolak: " + hasil.kode());
            }
            return "STRUK-" + pesanan.id();
        }
    }

    public static void main(String[] args) {
        FakePembayaran mock = new FakePembayaran();
        mock.jawabDengan(new HasilBayar(true, "OK-42")); // pasang jawaban
        Kasir kasir = new Kasir(mock);

        String struk = kasir.proses(new Pesanan("PSN-1", 250_000L));

        System.out.println("struk                    : " + struk);
        System.out.println("verify PSN-1 dipanggil   : " + mock.pernahMemanggil("PSN-1"));
        System.out.println("verify jumlah diteruskan : " + mock.jumlahUntuk("PSN-1"));
        System.out.println("verify PSN-9 dipanggil   : " + mock.pernahMemanggil("PSN-9"));
        System.out.println("total panggilan          : " + mock.totalPanggilan());

        // skenario kedua: jawaban penolakan dari gateway
        mock.jawabDengan(new HasilBayar(false, "KURANG-SALDO"));
        try {
            kasir.proses(new Pesanan("PSN-2", 500_000L));
        } catch (IllegalStateException e) {
            System.out.println("penolakan                : " + e.getMessage());
        }
        System.out.println("total panggilan          : " + mock.totalPanggilan());
    }
}
