import java.util.Objects;

public class RekeningKontrak {
    public static void main(String[] args) {
        Rekening budi = new Rekening("Budi", 500_000);
        Rekening siti = new Rekening("Siti", 100_000);

        budi.transfer(siti, 150_000);
        System.out.println("Saldo Budi: Rp" + budi.saldo());
        System.out.println("Saldo Siti: Rp" + siti.saldo());

        try {
            budi.transfer(null, 50_000); // melanggar prasyarat
        } catch (NullPointerException e) {
            System.out.println("Ditolak: " + e.getMessage());
        }

        try {
            budi.transfer(siti, 999_999); // melanggar prasyarat saldo
        } catch (IllegalArgumentException e) {
            System.out.println("Ditolak: " + e.getMessage());
        }
    }
}

class Rekening {
    private final String pemilik;
    private long saldo;

    Rekening(String pemilik, long saldoAwal) {
        this.pemilik = Objects.requireNonNull(pemilik, "pemilik tidak boleh null");
        if (saldoAwal < 0) {
            throw new IllegalArgumentException("saldo awal tidak boleh negatif");
        }
        this.saldo = saldoAwal;
    }

    /**
     * Memindahkan saldo ke rekening tujuan.
     *
     * Prasyarat : tujuan tidak null; jumlah positif; jumlah <= saldo rekening ini.
     * Jaminan   : saldo rekening ini berkurang tepat jumlah;
     *             saldo tujuan bertambah tepat jumlah;
     *             total dana kedua rekening tetap.
     */
    void transfer(Rekening tujuan, long jumlah) {
        Objects.requireNonNull(tujuan, "tujuan tidak boleh null");
        if (jumlah <= 0) {
            throw new IllegalArgumentException("jumlah harus positif: " + jumlah);
        }
        if (jumlah > saldo) {
            throw new IllegalArgumentException(
                    "saldo tidak cukup: Rp" + saldo + " < Rp" + jumlah);
        }

        long totalSebelum = this.saldo + tujuan.saldo;

        this.saldo -= jumlah;
        tujuan.saldo += jumlah;

        assert this.saldo + tujuan.saldo == totalSebelum : "total dana berubah";
        assert this.saldo >= 0 && tujuan.saldo >= 0 : "saldo negatif";
    }

    long saldo() {
        return saldo;
    }
}
