import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * Penghitung beban pipeline stream pada data tetap: kunjungan tahap
 * filter (terpisah vs gabungan) dan jumlah pembandingan sort sungguhan
 * lewat Comparator penghitung. Semua angka deterministik.
 */
public class BebanPipeline {

    public static void main(String[] args) {
        int n = 1000;

        // ---- Bagian 1: kunjungan tahap antara ----
        long[] kunjungan = {0};

        long hasilPisah = IntStream.rangeClosed(1, n)
            .filter(x -> {
                kunjungan[0]++;
                return x % 2 == 0;
            })
            .filter(x -> {
                kunjungan[0]++;
                return x > n / 2;
            })
            .count();
        long kunjunganPisah = kunjungan[0];

        kunjungan[0] = 0;
        long hasilGabung = IntStream.rangeClosed(1, n)
            .filter(x -> {
                kunjungan[0]++;
                return x % 2 == 0 && x > n / 2;
            })
            .count();
        long kunjunganGabung = kunjungan[0];

        System.out.println("== Bagian 1: kunjungan tahap filter (n = " + n + ") ==");
        System.out.println("filter terpisah : " + kunjunganPisah
            + " kunjungan tahap, hasil " + hasilPisah);
        System.out.println("filter gabungan : " + kunjunganGabung
            + " kunjungan tahap, hasil " + hasilGabung);
        System.out.println();

        // ---- Bagian 2: pembandingan pengurutan ----
        int[] banding = {0};
        Comparator<Integer> penghitung = (a, b) -> {
            banding[0]++;
            return Integer.compare(a, b);
        };

        List<Integer> menurun = new ArrayList<>();
        for (int i = n; i >= 1; i--) {
            menurun.add(i);
        }

        List<Integer> acak = new ArrayList<>();
        for (int i = 1; i <= n; i++) {
            acak.add(i);
        }
        Collections.shuffle(acak, new Random(42));

        banding[0] = 0;
        List<Integer> salinanAcak = new ArrayList<>(acak);
        salinanAcak.sort(penghitung);
        int bandingAcak = banding[0];

        banding[0] = 0;
        List<Integer> salinanTurun = new ArrayList<>(menurun);
        salinanTurun.sort(penghitung);
        int bandingTurun = banding[0];

        banding[0] = 0;
        List<Integer> menaik = new ArrayList<>();
        for (int i = 1; i <= n; i++) {
            menaik.add(i);
        }
        List<Integer> salinanNaik = new ArrayList<>(menaik);
        salinanNaik.sort(penghitung);
        int bandingNaik = banding[0];

        System.out.println("== Bagian 2: pembandingan pengurutan (n = " + n + ") ==");
        System.out.println("sorted() data acak            : " + bandingAcak + " pembandingan");
        System.out.println("sorted() data terurut menurun : " + bandingTurun
            + " pembandingan  <- run menurun dibalik, bukan diurut ulang");
        System.out.println("sorted() data terurut menaik  : " + bandingNaik
            + " pembandingan  <- TimSort memanfaatkan urutan yang ada");
        System.out.println("limit(5) tanpa sorted()       : 0 pembandingan");
        System.out.println();

        // ---- Kesimpulan ----
        System.out.println("== Kesimpulan ==");
        System.out.println("Predikat yang saling terkait lebih hemat digabung");
        System.out.println("dalam satu filter; sorted() paling murah ketika");
        System.out.println("kita tidak menambahnya sama sekali.");
    }
}
