import java.util.ArrayList;
import java.util.List;

public class PindaiDependensi {

    // Satu dependensi proyek: nama artefak dan versi terpasang.
    record Dependensi(String artefak, String versi) { }

    // Satu entri kerentanan: rentang versi terdampak (mulai sampai sebelum
    // batas), versi perbaikan, dan deskripsi singkatnya.
    record Cve(String id, String artefak, String mulai, String batas,
               String perbaikan, String deskripsi) { }

    // Basis pengetahuan mini dua entri - versi sederhana dari database CVE.
    private static final List<Cve> BASIS_CVE = List.of(
            new Cve("CVE-2021-44228", "log4j-core", "2.0", "2.16.0", "2.17.1",
                    "Log4Shell: JNDI lookup pada pesan log memicu unduh dan eksekusi class"),
            new Cve("CVE-2015-7501", "commons-collections", "3.0", "3.2.2", "3.2.2",
                    "InvokerTransformer pada deserialisasi memicu eksekusi perintah"));

    public static void main(String[] args) {
        List<Dependensi> proyek = List.of(
                new Dependensi("log4j-core", "2.14.1"),
                new Dependensi("commons-collections", "3.2.1"),
                new Dependensi("jackson-databind", "2.15.0"),
                new Dependensi("log4j-core", "2.17.1"));

        System.out.println("=== Pemindaian " + proyek.size() + " dependensi "
                + "(basis " + BASIS_CVE.size() + " CVE) ===");
        int temuan = 0;
        for (Dependensi d : proyek) {
            List<Cve> kena = cariTemuan(d);
            if (kena.isEmpty()) {
                System.out.println(d.artefak() + " " + d.versi()
                        + " -> aman (tidak ada temuan)");
            } else {
                for (Cve c : kena) {
                    temuan++;
                    System.out.println(d.artefak() + " " + d.versi()
                            + " -> RENTAN " + c.id() + " (perbaikan: " + c.perbaikan() + ")");
                    System.out.println("    " + c.deskripsi());
                }
            }
        }
        System.out.println("Temuan: " + temuan + " kerentanan");
    }

    static List<Cve> cariTemuan(Dependensi d) {
        List<Cve> kena = new ArrayList<>();
        for (Cve c : BASIS_CVE) {
            if (!c.artefak().equals(d.artefak())) {
                continue;
            }
            boolean diAtasAtauSama = bandingkanVersi(d.versi(), c.mulai()) >= 0;
            boolean diBawahBatas = bandingkanVersi(d.versi(), c.batas()) < 0;
            if (diAtasAtauSama && diBawahBatas) {
                kena.add(c);
            }
        }
        return kena;
    }

    // Bandingkan versi numerik bertitik: 2.14.1 < 2.16.0 < 2.17.1.
    static int bandingkanVersi(String a, String b) {
        String[] bagianA = a.split("\\.");
        String[] bagianB = b.split("\\.");
        int panjang = Math.max(bagianA.length, bagianB.length);
        for (int i = 0; i < panjang; i++) {
            int na = i < bagianA.length ? Integer.parseInt(bagianA[i]) : 0;
            int nb = i < bagianB.length ? Integer.parseInt(bagianB[i]) : 0;
            if (na != nb) {
                return Integer.compare(na, nb);
            }
        }
        return 0;
    }
}
