import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class BelanjaDenganRepo {
    public static void main(String[] args) {
        RepoKeranjang repo = new RepoKeranjangMemori();
        LayananBelanja layanan = new LayananBelanja(repo);

        layanan.mulaiBelanja("KR-01", "Budi");
        layanan.mulaiBelanja("KR-02", "Siti");
        layanan.tambahItem("KR-01", "Buku Java", 2);

        // Kode domain bicara bahasa koleksi, bukan bahasa tabel dan SQL
        System.out.println(repo.cari("KR-01").map(Keranjang::ringkas).orElse("tidak ada"));
        System.out.println("jumlah keranjang terdaftar: " + repo.semuanya().size());
    }
}

// Aggregate yang disimpan utuh lewat root-nya
record Keranjang(String id, String pembeli, List<ItemBelanja> items) {
    Keranjang {
        items = List.copyOf(items);
    }

    static Keranjang kosong(String id, String pembeli) {
        return new Keranjang(id, pembeli, List.of());
    }

    Keranjang tambah(String nama, int jumlah) {
        List<ItemBelanja> baru = new ArrayList<>(items);
        baru.add(new ItemBelanja(nama, jumlah));
        return new Keranjang(id, pembeli, baru);
    }

    String ringkas() {
        return id + " milik " + pembeli + ": " + items.size() + " jenis item";
    }
}

record ItemBelanja(String nama, int jumlah) {
}

// Kontrak repository: kosakata koleksi domain
interface RepoKeranjang {
    void simpan(Keranjang keranjang);

    Optional<Keranjang> cari(String id);

    List<Keranjang> semuanya();
}

// Implementasi in-memory: cukup untuk pengujian dan prototipe
class RepoKeranjangMemori implements RepoKeranjang {
    private final Map<String, Keranjang> data = new LinkedHashMap<>();

    @Override
    public void simpan(Keranjang keranjang) {
        data.put(keranjang.id(), keranjang);
    }

    @Override
    public Optional<Keranjang> cari(String id) {
        return Optional.ofNullable(data.get(id));
    }

    @Override
    public List<Keranjang> semuanya() {
        return List.copyOf(data.values());
    }
}

// Layanan domain mengandalkan kontrak, bukan implementasi tertentu
class LayananBelanja {
    private final RepoKeranjang repo;

    LayananBelanja(RepoKeranjang repo) {
        this.repo = repo;
    }

    void mulaiBelanja(String id, String pembeli) {
        repo.simpan(Keranjang.kosong(id, pembeli));
    }

    void tambahItem(String id, String nama, int jumlah) {
        repo.cari(id).ifPresent(keranjang ->
                repo.simpan(keranjang.tambah(nama, jumlah)));
    }
}
