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

public class AplikasiRepository {

    public static void main(String[] args) {
        ProdukRepository repo = new ProdukRepositoryMemori();

        System.out.println("== Mengisi repository ==");
        repo.tambah(new Produk(0, "Buku Java Dasar", "buku", 150_000));
        repo.tambah(new Produk(0, "Mouse Wireless", "elektronik", 250_000));
        repo.tambah(new Produk(0, "Buku SQL Praktis", "buku", 180_000));
        repo.tambah(new Produk(0, "Pensil Mekanik", "alat-tulis", 75_000));
        Produk keyboard = repo.tambah(new Produk(0, "Keyboard Compact", "elektronik", 450_000));
        System.out.println("produk terdaftar : " + repo.semua().size());

        System.out.println();
        System.out.println("== Kueri bermakna domain ==");
        System.out.println("cariByKategori(\"buku\")     : " + ringkas(repo.cariByKategori("buku")));
        System.out.println("cariHargaDiBawah(200000)  : " + ringkas(repo.cariHargaDiBawah(200_000)));
        System.out.println("cariKataKunci(\"java\")     : " + ringkas(repo.cariKataKunci("java")));

        System.out.println();
        System.out.println("== Semantik koleksi ==");
        System.out.println("hapus(keyboard) : " + repo.hapus(keyboard)
                + " -> sisa: " + repo.semua().size());
        System.out.println("cariById(5)     : " + repo.cariById(5));
    }

    static List<String> ringkas(List<Produk> daftar) {
        List<String> hasil = new ArrayList<>();
        for (Produk p : daftar) {
            hasil.add("#" + p.id() + " " + p.nama() + " (" + p.harga() + ")");
        }
        return hasil;
    }
}

/** Entitas domain: kaya makna bisnis, bukan cerminan kolom tabel. */
record Produk(long id, String nama, String kategori, long harga) {
}

/** Kontrak repository: bahasa domain, bukan bahasa tabel. */
interface ProdukRepository {

    Produk tambah(Produk p);

    Optional<Produk> cariById(long id);

    List<Produk> semua();

    List<Produk> cariByKategori(String kategori);

    List<Produk> cariHargaDiBawah(long batas);

    List<Produk> cariKataKunci(String kata);

    boolean hapus(Produk p);
}

/** Implementasi in-memory: koleksi objek domain sebagai sumber data. */
class ProdukRepositoryMemori implements ProdukRepository {

    private final Map<Long, Produk> data = new LinkedHashMap<>();
    private final AtomicLong urut = new AtomicLong();

    @Override
    public Produk tambah(Produk p) {
        long id = urut.incrementAndGet();
        Produk tersimpan = new Produk(id, p.nama(), p.kategori(), p.harga());
        data.put(id, tersimpan);
        return tersimpan;
    }

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

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

    @Override
    public List<Produk> cariByKategori(String kategori) {
        List<Produk> hasil = new ArrayList<>();
        for (Produk p : data.values()) {
            if (p.kategori().equals(kategori)) {
                hasil.add(p);
            }
        }
        return hasil;
    }

    @Override
    public List<Produk> cariHargaDiBawah(long batas) {
        List<Produk> hasil = new ArrayList<>();
        for (Produk p : data.values()) {
            if (p.harga() < batas) {
                hasil.add(p);
            }
        }
        return hasil;
    }

    @Override
    public List<Produk> cariKataKunci(String kata) {
        String k = kata.toLowerCase(Locale.ROOT);
        List<Produk> hasil = new ArrayList<>();
        for (Produk p : data.values()) {
            if (p.nama().toLowerCase(Locale.ROOT).contains(k)) {
                hasil.add(p);
            }
        }
        return hasil;
    }

    @Override
    public boolean hapus(Produk p) {
        return data.remove(p.id(), p); // hanya bila entitas yang sama pula tersimpan
    }
}
