import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public class TimAman {
    public static void main(String[] args) {
        Date berdiri = Date.from(
                LocalDate.of(2026, 1, 15).atStartOfDay(ZoneOffset.UTC).toInstant());

        System.out.println("== Class tanpa pertahanan ==");
        TimRentan rentan = new TimRentan();
        rentan.tambah("Budi");
        rentan.tambah("Siti");
        rentan.anggota().clear(); // referensi internal diubah dari luar
        System.out.println("Sisa anggota: " + rentan.anggota().size());

        System.out.println("== Class dengan defensive copy ==");
        TimAman aman = new TimAman("Backend", berdiri);
        aman.tambah("Budi");
        aman.tambah("Siti");

        List<String> snapshot = aman.anggota(); // salinan beku saat itu
        aman.tambah("Dewi");                    // internal berubah setelahnya
        System.out.println("Snapshot awal : " + snapshot);
        System.out.println("Isi terkini   : " + aman.anggota());

        berdiri.setTime(0); // Date milik pemanggil digeser, salinan internal aman
        System.out.println("Tahun berdiri : " + aman.tahunBerdiri());

        System.out.println("== Validasi di batas ==");
        try {
            aman.tambah(" ");
        } catch (IllegalArgumentException e) {
            System.out.println("Ditolak: " + e.getMessage());
        }
        try {
            new TimAman(null, berdiri);
        } catch (NullPointerException e) {
            System.out.println("Ditolak: " + e.getMessage());
        }
    }

    private final String nama;
    private final Date berdiri;
    private final List<String> anggota = new ArrayList<>();

    TimAman(String nama, Date berdiri) {
        this.nama = Objects.requireNonNull(nama, "nama tim tidak boleh null");
        Objects.requireNonNull(berdiri, "tanggal berdiri tidak boleh null");
        this.berdiri = new Date(berdiri.getTime()); // salin saat masuk
    }

    void tambah(String namaAnggota) {
        Objects.requireNonNull(namaAnggota, "nama anggota tidak boleh null");
        if (namaAnggota.isBlank()) {
            throw new IllegalArgumentException("nama anggota tidak boleh kosong");
        }
        anggota.add(namaAnggota);
    }

    List<String> anggota() {
        return List.copyOf(anggota); // salinan yang tidak dapat diubah
    }

    Date berdiriSejak() {
        return new Date(berdiri.getTime()); // salinan baru setiap panggilan
    }

    int tahunBerdiri() {
        return berdiri.toInstant().atZone(ZoneOffset.UTC).getYear();
    }
}

class TimRentan {
    private final List<String> anggota = new ArrayList<>();

    void tambah(String nama) {
        anggota.add(nama);
    }

    List<String> anggota() {
        return anggota; // bocor: referensi internal dikembalikan langsung
    }
}
