import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;

public class AplikasiDao {

    public static void main(String[] args) {
        PenggunaDao dao = new PenggunaDaoMemori();

        // Create
        Pengguna budi = dao.simpan(new Pengguna(0, "Budi", "budi@example.com"));
        Pengguna siti = dao.simpan(new Pengguna(0, "Siti", "siti@example.com"));
        Pengguna dewi = dao.simpan(new Pengguna(0, "Dewi", "dewi@example.com"));
        System.out.println("simpan  : " + budi + ", " + siti + ", " + dewi);

        // Read
        System.out.println("cari 1  : " + dao.cariById(1).orElse(null));
        System.out.println("cari 99 : " + dao.cariById(99));
        System.out.println("semua   : " + dao.semua());

        // Update
        boolean ubah = dao.perbarui(2, new Pengguna(2, "Siti A.", "siti@example.com"));
        System.out.println("perbarui: " + ubah + " -> " + dao.cariById(2).orElse(null));

        // Delete
        boolean hapus = dao.hapus(3);
        System.out.println("hapus   : " + ubahTeks(hapus) + " -> jumlah sekarang: "
                + dao.semua().size());
    }

    static String ubahTeks(boolean b) {
        return b ? "berhasil" : "gagal";
    }
}

/** Transfer object: membawa data antara aplikasi dan DAO. */
record Pengguna(long id, String nama, String email) {
}

/** Kontrak akses data untuk entitas Pengguna. */
interface PenggunaDao {

    Pengguna simpan(Pengguna p);                 // INSERT

    Optional<Pengguna> cariById(long id);         // SELECT ... WHERE id = ?

    List<Pengguna> semua();                      // SELECT seluruh baris

    boolean perbarui(long id, Pengguna pBaru);   // UPDATE ... WHERE id = ?

    boolean hapus(long id);                      // DELETE ... WHERE id = ?
}

/** Implementasi in-memory: pengganti tabel database saat belajar. */
class PenggunaDaoMemori implements PenggunaDao {

    private final Map<Long, Pengguna> tabel = new LinkedHashMap<>();
    private final AtomicLong urut = new AtomicLong();

    @Override
    public Pengguna simpan(Pengguna p) {
        long id = urut.incrementAndGet();
        Pengguna tersimpan = new Pengguna(id, p.nama(), p.email());
        tabel.put(id, tersimpan);
        return tersimpan;
    }

    @Override
    public Optional<Pengguna> cariById(long id) {
        return Optional.ofNullable(tabel.get(id));
    }

    @Override
    public List<Pengguna> semua() {
        return new ArrayList<>(tabel.values());
    }

    @Override
    public boolean perbarui(long id, Pengguna pBaru) {
        return tabel.replace(id, pBaru) != null;
    }

    @Override
    public boolean hapus(long id) {
        return tabel.remove(id) != null;
    }
}
