import java.util.List;
import java.util.Map;

public class RantaiFilter {

    record Permintaan(String method, String path, String token, String csrf) { }

    interface Filter {
        String nama();

        // null = lanjut ke filter berikutnya; non-null = alasan penolakan.
        String proses(Permintaan p);
    }

    // Filter pertama: CORS memeriksa asal permintaan.
    static class FilterCors implements Filter {
        @Override
        public String nama() { return "CorsFilter"; }

        @Override
        public String proses(Permintaan p) {
            return null; // asal diizinkan untuk demo
        }
    }

    // CSRF: method penulisan wajib membawa token CSRF.
    static class FilterCsrf implements Filter {
        @Override
        public String nama() { return "CsrfFilter"; }

        @Override
        public String proses(Permintaan p) {
            boolean methodTulis = "POST".equals(p.method()) || "PUT".equals(p.method())
                    || "DELETE".equals(p.method()) || "PATCH".equals(p.method());
            if (methodTulis && (p.csrf() == null || p.csrf().isBlank())) {
                return "token CSRF hilang untuk method " + p.method();
            }
            return null;
        }
    }

    // Authentication: identitas wajib ada.
    static class FilterAuth implements Filter {
        private final Map<String, String> tokenKePengguna = Map.of(
                "token-budi", "budi",
                "token-admin", "admin");

        @Override
        public String nama() { return "AuthenticationFilter"; }

        @Override
        public String proses(Permintaan p) {
            if (p.token() == null || !tokenKePengguna.containsKey(p.token())) {
                return "tidak terautentikasi";
            }
            return null;
        }
    }

    // Authorization: aturan akses per pola path.
    static class FilterOtorisasi implements Filter {
        private final Map<String, String> tokenKePeran = Map.of(
                "token-budi", "USER",
                "token-admin", "ADMIN");

        @Override
        public String nama() { return "AuthorizationFilter"; }

        @Override
        public String proses(Permintaan p) {
            String peran = p.token() == null ? null : tokenKePeran.get(p.token());
            if (p.path().startsWith("/api/admin") && !"ADMIN".equals(peran)) {
                return "peran " + peran + " tidak berhak";
            }
            return null;
        }
    }

    public static void main(String[] args) {
        List<Filter> rantai = List.of(
                new FilterCors(),
                new FilterCsrf(),
                new FilterAuth(),
                new FilterOtorisasi());

        layani(rantai, new Permintaan("GET", "/api/produk", "token-budi", null));
        layani(rantai, new Permintaan("POST", "/api/produk", "token-budi", null));
        layani(rantai, new Permintaan("GET", "/api/produk", null, null));
        layani(rantai, new Permintaan("GET", "/api/admin/log", "token-budi", null));
        layani(rantai, new Permintaan("GET", "/api/admin/log", "token-admin", null));
    }

    // SecurityFilterChain mini: proses berurutan, tolakan memutus rantai.
    static void layani(List<Filter> rantai, Permintaan p) {
        System.out.println("Request " + p.method() + " " + p.path()
                + " token=" + p.token() + " csrf=" + p.csrf());
        for (Filter f : rantai) {
            String penolakan = f.proses(p);
            System.out.println("  " + f.nama() + " -> "
                    + (penolakan == null ? "lanjut" : "TOLAK (" + penolakan + ")"));
            if (penolakan != null) {
                System.out.println("  respons: 403 Forbidden, handler tidak terpanggil");
                System.out.println();
                return;
            }
        }
        System.out.println("  respons: 200 OK, handler dipanggil");
        System.out.println();
    }
}
