public class RakitServer {
    public static void main(String[] args) {
        // Konfigurasi lengkap: builder menyusun langkah demi langkah
        ServerWeb produksi = new ServerWeb.Builder("api.example.com", 443)
                .tls(true)
                .batasKoneksi(200)
                .timeoutBacaMillis(3_000)
                .gzip(true)
                .build();
        System.out.println("produksi : " + produksi);

        // Konfigurasi pengembangan: parameter opsional memakai nilai bawaan
        ServerWeb pengembangan = new ServerWeb.Builder("localhost", 8080).build();
        System.out.println("dev      : " + pengembangan);

        // Validasi terjadi di build(), bukan tersebar di banyak constructor
        try {
            new ServerWeb.Builder("api.example.com", 99_999).build();
        } catch (IllegalArgumentException e) {
            System.out.println("ditolak  : " + e.getMessage());
        }
    }
}

class ServerWeb {
    private final String host;
    private final int port;
    private final boolean tls;
    private final int batasKoneksi;
    private final int timeoutBacaMillis;
    private final boolean gzip;

    private ServerWeb(Builder b) {
        this.host = b.host;
        this.port = b.port;
        this.tls = b.tls;
        this.batasKoneksi = b.batasKoneksi;
        this.timeoutBacaMillis = b.timeoutBacaMillis;
        this.gzip = b.gzip;
    }

    @Override
    public String toString() {
        return host + ":" + port + " [tls=" + tls + ", koneksi=" + batasKoneksi
                + ", timeoutBaca=" + timeoutBacaMillis + "ms, gzip=" + gzip + "]";
    }

    // Builder: merakit objek banyak parameter dengan method berantai
    static class Builder {
        private final String host;
        private final int port;
        private boolean tls = false;
        private int batasKoneksi = 50;
        private int timeoutBacaMillis = 30_000;
        private boolean gzip = false;

        Builder(String host, int port) {
            this.host = host;
            this.port = port;
        }

        Builder tls(boolean aktif) {
            this.tls = aktif;
            return this;
        }

        Builder batasKoneksi(int jumlah) {
            this.batasKoneksi = jumlah;
            return this;
        }

        Builder timeoutBacaMillis(int millis) {
            this.timeoutBacaMillis = millis;
            return this;
        }

        Builder gzip(boolean aktif) {
            this.gzip = aktif;
            return this;
        }

        // Pusat validasi: objek lahir dalam keadaan valid atau tidak lahir sama sekali
        ServerWeb build() {
            if (port < 1 || port > 65_535) {
                throw new IllegalArgumentException(
                        "port harus 1 sampai 65535, diterima: " + port);
            }
            if (batasKoneksi < 1) {
                throw new IllegalArgumentException("batas koneksi minimal 1");
            }
            if (timeoutBacaMillis < 1) {
                throw new IllegalArgumentException("timeout baca harus positif");
            }
            if (tls && port != 443) {
                throw new IllegalArgumentException("tls aktif mengharuskan port 443");
            }
            return new ServerWeb(this);
        }
    }
}
