import java.util.LinkedHashMap;
import java.util.Map;

public class TabelRute {

    record Rute(String method, String pola) { }

    private final Map<Rute, String> handler = new LinkedHashMap<>();

    public static void main(String[] args) {
        TabelRute tabel = new TabelRute();
        tabel.daftar("GET", "/produk", "ProdukController.semua()");
        tabel.daftar("GET", "/produk/{id}", "ProdukController.satu(id)");
        tabel.daftar("POST", "/produk", "ProdukController.simpan()");
        tabel.daftar("PUT", "/produk/{id}", "ProdukController.perbarui(id)");
        tabel.daftar("DELETE", "/produk/{id}", "ProdukController.hapus(id)");

        tabel.cocokkan("GET /produk");
        tabel.cocokkan("GET /produk/17");
        tabel.cocokkan("PUT /produk/17");
        tabel.cocokkan("PATCH /produk/17");
        tabel.cocokkan("GET /produk/17/ulasan");
    }

    void daftar(String method, String pola, String handlerDescriptor) {
        handler.put(new Rute(method, pola), handlerDescriptor);
    }

    void cocokkan(String permintaan) {
        System.out.println("Request: " + permintaan);
        String[] bagian = permintaan.split(" ", 2);
        String method = bagian[0];
        String path = bagian[1];

        // Pass 1: method dan path harus cocok penuh.
        for (Map.Entry<Rute, String> e : handler.entrySet()) {
            Map<String, String> variabel = cocok(method, path, e.getKey());
            if (variabel != null) {
                System.out.println("  -> handler : " + e.getValue());
                variabel.forEach((k, v) -> System.out.println("  -> @" + k + " = " + v));
                System.out.println();
                return;
            }
        }

        // Pass 2: path cocok tetapi method salah -> 405.
        for (Map.Entry<Rute, String> e : handler.entrySet()) {
            if (cocok("GET", path, e.getKey()) != null || cocok("POST", path, e.getKey()) != null
                    || cocok("PUT", path, e.getKey()) != null || cocok("DELETE", path, e.getKey()) != null) {
                System.out.println("  -> 405 Method Not Allowed (method " + method
                        + " tidak terdaftar untuk path ini)");
                System.out.println();
                return;
            }
        }

        System.out.println("  -> 404 Not Found (tidak ada rute yang cocok)");
        System.out.println();
    }

    // Pencocokkan pola "/produk/{id}" terhadap "/produk/17".
    Map<String, String> cocok(String method, String path, Rute rute) {
        if (!rute.method().equals(method)) {
            return null;
        }
        String[] segPermintaan = path.split("/");
        String[] segPola = rute.pola().split("/");
        if (segPermintaan.length != segPola.length) {
            return null;
        }
        Map<String, String> variabel = new LinkedHashMap<>();
        for (int i = 0; i < segPola.length; i++) {
            String pola = segPola[i];
            String aktual = segPermintaan[i];
            if (pola.startsWith("{") && pola.endsWith("}")) {
                variabel.put("PathVariable " + pola.substring(1, pola.length() - 1), aktual);
            } else if (!pola.equals(aktual)) {
                return null;
            }
        }
        return variabel;
    }
}
