import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ValidasiMini {

    // Mirror Bean Validation: @NotBlank, @Size(min=), @Email, @Positive.
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface TidakKosong { }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface PanjangMin {
        int nilai();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface Surel { }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface Positif { }

    static class FormulirPendaftaran {
        @TidakKosong
        @PanjangMin(nilai = 3)
        String nama;

        @Surel
        String email;

        @Positif
        int umur;

        FormulirPendaftaran(String nama, String email, int umur) {
            this.nama = nama;
            this.email = email;
            this.umur = umur;
        }
    }

    public static void main(String[] args) throws Exception {
        validasi(new FormulirPendaftaran("Budi", "budi@example.com", 25));
        validasi(new FormulirPendaftaran("Si", "budi-example", -1));
    }

    static void validasi(FormulirPendaftaran formulir) throws Exception {
        System.out.println("Validasi: nama='" + formulir.nama + "' email='"
                + formulir.email + "' umur=" + formulir.umur);

        List<String> pelanggaran = new ArrayList<>();
        for (Field f : formulir.getClass().getDeclaredFields()) {
            f.setAccessible(true);
            Object nilai = f.get(formulir);

            if (f.isAnnotationPresent(TidakKosong.class)
                    && (nilai == null || nilai.toString().isBlank())) {
                pelanggaran.add(f.getName() + ": tidak boleh kosong");
            }
            if (f.isAnnotationPresent(PanjangMin.class) && nilai != null
                    && nilai.toString().length() < f.getAnnotation(PanjangMin.class).nilai()) {
                pelanggaran.add(f.getName() + ": panjang minimal "
                        + f.getAnnotation(PanjangMin.class).nilai());
            }
            if (f.isAnnotationPresent(Surel.class)
                    && (nilai == null || !nilai.toString().matches(".+@.+\\..+"))) {
                pelanggaran.add(f.getName() + ": format email tidak valid");
            }
            if (f.isAnnotationPresent(Positif.class) && ((Integer) nilai) <= 0) {
                pelanggaran.add(f.getName() + ": harus bilangan positif");
            }
        }

        if (pelanggaran.isEmpty()) {
            System.out.println("  HASIL: valid -> 200 OK");
        } else {
            System.out.println("  HASIL: ditolak -> 400 Bad Request");
            for (String p : pelanggaran) {
                System.out.println("  - " + p);
            }
        }
        System.out.println();
    }
}
