import java.util.List;

public class LaporanPabrik {
    public static void main(String[] args) {
        List<Penjualan> data = List.of(
                new Penjualan("Buku", 3, 85_000),
                new Penjualan("Pena", 10, 12_000));

        // Klien bebas switch: satu panggilan untuk setiap tipe laporan
        for (TipeLaporan tipe : TipeLaporan.values()) {
            Laporan laporan = PabrikLaporan.buat(tipe, data);
            System.out.println("== " + tipe + " ==");
            System.out.println(laporan.render());
        }

        // Static factory sebagai "named constructor": nama method menjelaskan maksud
        Laporan ringkas = LaporanCsv.satuBaris(data);
        System.out.println("== CSV satu baris ==");
        System.out.println(ringkas.render());
    }
}

enum TipeLaporan { TEKS, CSV }

interface Laporan {
    String render();
}

record Penjualan(String produk, int jumlah, long hargaSatuan) {
    long total() {
        return (long) jumlah * hargaSatuan;
    }
}

// Simple factory: satu-satunya tempat yang mengenal seluruh concrete class
class PabrikLaporan {
    static Laporan buat(TipeLaporan tipe, List<Penjualan> data) {
        return switch (tipe) {
            case TEKS -> new LaporanTeks(data);
            case CSV -> LaporanCsv.dari(data);
        };
    }
}

class LaporanTeks implements Laporan {
    private final List<Penjualan> data;

    LaporanTeks(List<Penjualan> data) {
        this.data = data;
    }

    @Override
    public String render() {
        StringBuilder teks = new StringBuilder();
        for (Penjualan p : data) {
            teks.append(p.produk()).append(" x").append(p.jumlah())
                    .append(" = Rp").append(p.total()).append('\n');
        }
        teks.append("total: Rp").append(totalSemua());
        return teks.toString();
    }

    private long totalSemua() {
        long total = 0;
        for (Penjualan p : data) {
            total += p.total();
        }
        return total;
    }
}

class LaporanCsv implements Laporan {
    private final List<Penjualan> data;
    private final boolean ringkasSatuBaris;

    private LaporanCsv(List<Penjualan> data, boolean ringkasSatuBaris) {
        this.data = data;
        this.ringkasSatuBaris = ringkasSatuBaris;
    }

    // Named constructor untuk kebutuhan biasa
    static LaporanCsv dari(List<Penjualan> data) {
        return new LaporanCsv(data, false);
    }

    // Named constructor untuk kebutuhan ringkas
    static LaporanCsv satuBaris(List<Penjualan> data) {
        return new LaporanCsv(data, true);
    }

    @Override
    public String render() {
        if (ringkasSatuBaris) {
            return data.size() + " baris data, total Rp" + totalSemua();
        }
        StringBuilder teks = new StringBuilder("produk,jumlah,total\n");
        for (Penjualan p : data) {
            teks.append(p.produk()).append(',').append(p.jumlah())
                    .append(',').append(p.total()).append('\n');
        }
        return teks.toString();
    }

    private long totalSemua() {
        long total = 0;
        for (Penjualan p : data) {
            total += p.total();
        }
        return total;
    }
}
