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

public class ApiProduk {

    // ==== Lapisan domain: bentuk data yang dipertukarkan ====
    record DtoProduk(String nama, long harga) { }

    record Produk(long id, String nama, long harga) { }

    // Respons HTTP mini: status, header Location, dan isi badan.
    record Respons(int status, String lokasi, String isi) { }

    // ==== Lapisan repository: satu-satunya yang menyentuh penyimpanan ====
    static class RepoProduk {

        private final Map<Long, Produk> tabel = new LinkedHashMap<>();
        private long urut = 0;

        Produk tambah(DtoProduk dto) {
            Produk p = new Produk(++urut, dto.nama(), dto.harga());
            tabel.put(p.id(), p);
            return p;
        }

        Optional<Produk> cari(long id) {
            return Optional.ofNullable(tabel.get(id));
        }

        List<Produk> semua() {
            return List.copyOf(tabel.values());
        }

        Optional<Produk> ubah(long id, DtoProduk dto) {
            Produk baru = new Produk(id, dto.nama(), dto.harga());
            return tabel.replace(id, baru) == null
                    ? Optional.empty()
                    : Optional.of(baru);
        }

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

    // ==== Lapisan service: aturan bisnis dan validasi ====
    static class LayananProduk {

        private final RepoProduk repo;

        LayananProduk(RepoProduk repo) {
            this.repo = repo;
        }

        List<String> validasi(DtoProduk dto) {
            List<String> galat = new ArrayList<>();
            if (dto.nama() == null || dto.nama().isBlank()) {
                galat.add("nama tidak boleh kosong");
            }
            if (dto.harga() <= 0) {
                galat.add("harga harus positif");
            }
            return galat;
        }

        List<Produk> semua() {
            return repo.semua();
        }

        Optional<Produk> cari(long id) {
            return repo.cari(id);
        }

        Produk tambah(DtoProduk dto) {
            return repo.tambah(dto);
        }

        Optional<Produk> ubah(long id, DtoProduk dto) {
            return repo.ubah(id, dto);
        }

        boolean hapus(long id) {
            return repo.hapus(id);
        }
    }

    // ==== Lapisan controller: penterjemah request -> Respons ====
    static class KontrolProduk {

        private final LayananProduk layanan;

        KontrolProduk(LayananProduk layanan) {
            this.layanan = layanan;
        }

        Respons semua() {
            return new Respons(200, null, layanan.semua().toString());
        }

        Respons satu(long id) {
            return layanan.cari(id)
                    .map(p -> new Respons(200, null, p.toString()))
                    .orElseGet(() -> new Respons(404, null, "{\"galat\":\"produk tidak ditemukan\"}"));
        }

        Respons buat(DtoProduk dto) {
            List<String> galat = layanan.validasi(dto);
            if (!galat.isEmpty()) {
                return new Respons(400, null, "{\"galat\":" + galat + "}");
            }
            Produk p = layanan.tambah(dto);
            return new Respons(201, "/api/produk/" + p.id(), p.toString());
        }

        Respons ubah(long id, DtoProduk dto) {
            List<String> galat = layanan.validasi(dto);
            if (!galat.isEmpty()) {
                return new Respons(400, null, "{\"galat\":" + galat + "}");
            }
            return layanan.ubah(id, dto)
                    .map(p -> new Respons(200, null, p.toString()))
                    .orElseGet(() -> new Respons(404, null, "{\"galat\":\"produk tidak ditemukan\"}"));
        }

        Respons hapus(long id) {
            return layanan.hapus(id)
                    ? new Respons(204, null, "")
                    : new Respons(404, null, "{\"galat\":\"produk tidak ditemukan\"}");
        }
    }

    // ==== Router mini ala DispatcherServlet ====
    static class Router {

        private final KontrolProduk kontrol;

        Router(KontrolProduk kontrol) {
            this.kontrol = kontrol;
        }

        Respons arahkan(String method, String path, String body) {
            String[] segmen = path.split("/");
            // path selalu berbentuk /api/produk[/id]
            if (segmen.length == 3 && segmen[1].equals("api") && segmen[2].equals("produk")) {
                return switch (method) {
                    case "GET" -> kontrol.semua();
                    case "POST" -> kontrol.buat(parse(body));
                    default -> new Respons(405, null, "");
                };
            }
            if (segmen.length == 4 && segmen[2].equals("produk")) {
                long id = Long.parseLong(segmen[3]);
                return switch (method) {
                    case "GET" -> kontrol.satu(id);
                    case "PUT" -> kontrol.ubah(id, parse(body));
                    case "DELETE" -> kontrol.hapus(id);
                    default -> new Respons(405, null, "");
                };
            }
            return new Respons(404, null, "");
        }

        // Format badan sederhana: nama=...;harga=...
        static DtoProduk parse(String body) {
            String nama = null;
            long harga = 0;
            for (String pasangan : body.split(";")) {
                String[] kv = pasangan.split("=", 2);
                if (kv.length == 2) {
                    if (kv[0].trim().equals("nama")) nama = kv[1];
                    if (kv[0].trim().equals("harga")) harga = Long.parseLong(kv[1]);
                }
            }
            return new DtoProduk(nama, harga);
        }
    }

    public static void main(String[] args) {
        Router router = new Router(new KontrolProduk(new LayananProduk(new RepoProduk())));

        kirim(router, "GET", "/api/produk", null);
        kirim(router, "POST", "/api/produk", "nama=Kopi Gayo 250g;harga=85000");
        kirim(router, "POST", "/api/produk", "nama=Teh Melati 100g;harga=45000");
        kirim(router, "POST", "/api/produk", "nama=;harga=-1");
        kirim(router, "GET", "/api/produk", null);
        kirim(router, "GET", "/api/produk/1", null);
        kirim(router, "GET", "/api/produk/99", null);
        kirim(router, "PUT", "/api/produk/2", "nama=Teh Melati 100g;harga=50000");
        kirim(router, "PUT", "/api/produk/99", "nama=X;harga=1");
        kirim(router, "DELETE", "/api/produk/1", null);
        kirim(router, "DELETE", "/api/produk/1", null);
        kirim(router, "GET", "/api/produk", null);
    }

    static void kirim(Router router, String method, String path, String body) {
        Respons r = router.arahkan(method, path, body == null ? "" : body);
        StringBuilder baris = new StringBuilder(
                String.format("%-7s %-18s -> %d", method, path, r.status()));
        if (r.lokasi() != null) {
            baris.append("  Location: ").append(r.lokasi());
        }
        if (!r.isi().isEmpty()) {
            baris.append("  isi: ").append(r.isi());
        }
        System.out.println(baris);
    }
}
