import java.math.BigDecimal;
import java.time.YearMonth;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/** Kumpulan operasi analisis berbasis Stream API untuk daftar transaksi. */
public final class AnalisisKeuangan {

    private AnalisisKeuangan() {
        // Kelas utilitas: seluruh anggota static, tidak perlu instance.
    }

    /** Collector penjumlah nominal — padanan summingInt untuk uang BigDecimal. */
    public static Collector<Transaksi, ?, BigDecimal> penjumlahan() {
        return Collectors.reducing(BigDecimal.ZERO, Transaksi::jumlah, BigDecimal::add);
    }

    /** Laporan lengkap per bulan: groupingBy berjenjang dengan teeing + filtering. */
    public static Map<YearMonth, LaporanBulanan> laporanPerBulan(List<Transaksi> transaksi) {
        return transaksi.stream()
                .collect(Collectors.groupingBy(
                        Transaksi::bulan,
                        TreeMap::new,
                        Collectors.teeing(
                                Collectors.filtering(
                                        t -> t.jenis() == JenisTransaksi.PEMASUKAN, penjumlahan()),
                                Collectors.filtering(
                                        t -> t.jenis() == JenisTransaksi.PENGELUARAN, penjumlahan()),
                                LaporanBulanan::new)));
    }

    /** Total pengeluaran per kategori pada satu bulan: groupingBy + reducing. */
    public static Map<String, BigDecimal> pengeluaranPerKategori(List<Transaksi> transaksi,
                                                                 YearMonth bulan) {
        return transaksi.stream()
                .filter(t -> t.jenis() == JenisTransaksi.PENGELUARAN)
                .filter(t -> t.bulan().equals(bulan))
                .collect(Collectors.groupingBy(Transaksi::kategori, penjumlahan()));
    }

    /** Memecah pengeluaran satu bulan menjadi dua kelompok: di atas dan di bawah ambang. */
    public static Map<Boolean, List<Transaksi>> partisiNominal(List<Transaksi> transaksi,
                                                               YearMonth bulan,
                                                               BigDecimal ambang) {
        return transaksi.stream()
                .filter(t -> t.jenis() == JenisTransaksi.PENGELUARAN)
                .filter(t -> t.bulan().equals(bulan))
                .collect(Collectors.partitioningBy(
                        t -> t.jumlah().compareTo(ambang) > 0));
    }
}
