import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/** Bagian 2: kategori terdaftar, anggaran bulanan, dan validasi silang. */
public class DemoKeuangan {

    public static void main(String[] args) throws KategoriTidakTerdahtarException {
        BukuKas kas = new BukuKas();
        daftarkanKategori(kas);
        for (Transaksi t : contohTransaksi()) {
            kas.tambah(t);
        }
        System.out.println("Kategori terdaftar : 6");
        System.out.println("Transaksi tercatat : " + kas.jumlahTransaksi());

        // Dua upaya menyalahi aturan kategori, keduanya tertolak.
        cobaTambah(kas, new Transaksi(LocalDate.of(2026, 2, 3), "Beli obat demam",
                JenisTransaksi.PENGELUARAN, "Kesehatan", new BigDecimal("45000.00")));
        cobaTambah(kas, new Transaksi(LocalDate.of(2026, 2, 20), "Bonus proyek desain",
                JenisTransaksi.PEMASUKAN, "Makanan", new BigDecimal("500000.00")));

        System.out.println();
        cetakAnggaran(kas, YearMonth.of(2026, 1));
        System.out.println();
        cetakAnggaran(kas, YearMonth.of(2026, 2));
        System.out.println();
        System.out.printf(Locale.US, "Saldo akhir per akhir Februari 2026: %,14.2f%n",
                kas.saldo());
    }

    /** Menambah satu transaksi dan melaporkan hasilnya tanpa menghentikan program. */
    private static void cobaTambah(BukuKas kas, Transaksi t) {
        try {
            kas.tambah(t);
            System.out.println("DITERIMA : " + t.keterangan());
        } catch (KategoriTidakTerdahtarException | IllegalArgumentException e) {
            System.out.println("DITOLAK  : " + e.getMessage());
        }
    }

    /** Mencetak tabel anggaran satu bulan: anggaran, realisasi, sisa, persen, status. */
    private static void cetakAnggaran(BukuKas kas, YearMonth bulan) {
        System.out.println("=== Laporan anggaran " + bulan + " ===");
        System.out.printf(Locale.US, "%-13s %13s %13s %13s %8s  %-8s%n",
                "Kategori", "Anggaran", "Realisasi", "Sisa", "Persen", "Status");
        Map<String, BigDecimal> realisasi = kas.realisasiPengeluaran(bulan);
        for (Kategori k : kas.kategoriBeranggaran()) {
            BigDecimal dipakai = realisasi.get(k.nama());
            BigDecimal sisa = k.anggaranBulanan().subtract(dipakai);
            BigDecimal persen = dipakai.multiply(BigDecimal.valueOf(100))
                    .divide(k.anggaranBulanan(), 1, RoundingMode.HALF_UP);
            System.out.printf(Locale.US, "%-13s %,13.2f %,13.2f %,13.2f %7s%%  %-8s%n",
                    k.nama(), k.anggaranBulanan(), dipakai, sisa,
                    persen.toPlainString(), status(persen));
        }
    }

    /** Status pemakaian anggaran: AMAN sampai 80%, WASPADA sampai 100%, LEBIH di atasnya. */
    private static String status(BigDecimal persen) {
        if (persen.compareTo(BigDecimal.valueOf(80)) <= 0) {
            return "AMAN";
        }
        if (persen.compareTo(BigDecimal.valueOf(100)) <= 0) {
            return "WASPADA";
        }
        return "LEBIH";
    }

    private static void daftarkanKategori(BukuKas kas) {
        kas.daftarkanKategori(new Kategori("Gaji", JenisTransaksi.PEMASUKAN, null));
        kas.daftarkanKategori(new Kategori("Freelance", JenisTransaksi.PEMASUKAN, null));
        kas.daftarkanKategori(new Kategori("Sewa", JenisTransaksi.PENGELUARAN,
                new BigDecimal("2500000.00")));
        kas.daftarkanKategori(new Kategori("Makanan", JenisTransaksi.PENGELUARAN,
                new BigDecimal("1500000.00")));
        kas.daftarkanKategori(new Kategori("Transportasi", JenisTransaksi.PENGELUARAN,
                new BigDecimal("600000.00")));
        kas.daftarkanKategori(new Kategori("Hiburan", JenisTransaksi.PENGELUARAN,
                new BigDecimal("500000.00")));
    }

    private static List<Transaksi> contohTransaksi() {
        return List.of(
                new Transaksi(LocalDate.of(2026, 1, 5), "Gaji bulanan Januari",
                        JenisTransaksi.PEMASUKAN, "Gaji", new BigDecimal("8500000.00")),
                new Transaksi(LocalDate.of(2026, 1, 7), "Sewa tempat tinggal Januari",
                        JenisTransaksi.PENGELUARAN, "Sewa", new BigDecimal("2500000.00")),
                new Transaksi(LocalDate.of(2026, 1, 10), "Belanja bahan makanan",
                        JenisTransaksi.PENGELUARAN, "Makanan", new BigDecimal("450000.00")),
                new Transaksi(LocalDate.of(2026, 1, 18), "Makan di luar bersama Siti",
                        JenisTransaksi.PENGELUARAN, "Makanan", new BigDecimal("380000.00")),
                new Transaksi(LocalDate.of(2026, 1, 22), "Isi bensin",
                        JenisTransaksi.PENGELUARAN, "Transportasi", new BigDecimal("350000.00")),
                new Transaksi(LocalDate.of(2026, 1, 28), "Langganan streaming",
                        JenisTransaksi.PENGELUARAN, "Hiburan", new BigDecimal("250000.00")),
                new Transaksi(LocalDate.of(2026, 2, 5), "Gaji bulanan Februari",
                        JenisTransaksi.PEMASUKAN, "Gaji", new BigDecimal("8500000.00")),
                new Transaksi(LocalDate.of(2026, 2, 7), "Sewa tempat tinggal Februari",
                        JenisTransaksi.PENGELUARAN, "Sewa", new BigDecimal("2500000.00")),
                new Transaksi(LocalDate.of(2026, 2, 12), "Belanja bahan makanan",
                        JenisTransaksi.PENGELUARAN, "Makanan", new BigDecimal("770000.00")),
                new Transaksi(LocalDate.of(2026, 2, 14), "Proyek desain lepas",
                        JenisTransaksi.PEMASUKAN, "Freelance", new BigDecimal("1200000.00")),
                new Transaksi(LocalDate.of(2026, 2, 18), "Makan di luar bersama Siti",
                        JenisTransaksi.PENGELUARAN, "Makanan", new BigDecimal("520000.00")),
                new Transaksi(LocalDate.of(2026, 2, 19), "Isi bensin",
                        JenisTransaksi.PENGELUARAN, "Transportasi", new BigDecimal("280000.00")),
                new Transaksi(LocalDate.of(2026, 2, 25), "Tiket konser musik",
                        JenisTransaksi.PENGELUARAN, "Hiburan", new BigDecimal("620000.00")));
    }
}
