import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

public class KlinikHexagonal {
    public static void main(String[] args) {
        System.out.println("== Adapter penyimpanan memori ==");
        jalankanSkenario(new PenyimpanMemori());

        System.out.println("== Adapter jejak audit ==");
        jalankanSkenario(new PenyimpanJejak());
    }

    static void jalankanSkenario(PenyimpanPasien penyimpan) {
        LayananPendaftaran layanan = new LayananPendaftaran(penyimpan);
        PendaftaranKonsol konsol = new PendaftaranKonsol(layanan);

        konsol.daftar("Budi", 30);
        konsol.daftar("Siti", 25);
        konsol.tampilkan("Budi");
        konsol.tampilkan("Dewi");
    }
}

// ===== Domain (pusat) =====
record Pasien(String nama, int umur) {
}

// Port keluar (driven): kebutuhan domain terhadap penyimpanan
interface PenyimpanPasien {
    void simpan(Pasien pasien);

    Optional<Pasien> cari(String nama);
}

// Use case domain: tidak mengenal teknologi apa pun
class LayananPendaftaran {
    private final PenyimpanPasien penyimpan;

    LayananPendaftaran(PenyimpanPasien penyimpan) {
        this.penyimpan = penyimpan;
    }

    String daftar(String nama, int umur) {
        if (nama == null || nama.isBlank()) {
            return "Pendaftaran gagal: nama kosong";
        }
        if (umur < 0) {
            return "Pendaftaran gagal: umur tidak valid";
        }
        penyimpan.simpan(new Pasien(nama.trim(), umur));
        return "Terdaftar: " + nama.trim();
    }

    Optional<Pasien> cari(String nama) {
        return penyimpan.cari(nama);
    }
}

// ===== Adapter masuk (driving): menyampaikan permintaan =====
class PendaftaranKonsol {
    private final LayananPendaftaran layanan;

    PendaftaranKonsol(LayananPendaftaran layanan) {
        this.layanan = layanan;
    }

    void daftar(String nama, int umur) {
        System.out.println(layanan.daftar(nama, umur));
    }

    void tampilkan(String nama) {
        System.out.println(layanan.cari(nama)
                .map(p -> "Ditemukan: " + p.nama() + " (" + p.umur() + " tahun)")
                .orElse("Tidak ditemukan: " + nama));
    }
}

// ===== Adapter keluar (driven): implementasi A =====
class PenyimpanMemori implements PenyimpanPasien {
    private final Map<String, Pasien> data = new LinkedHashMap<>();

    public void simpan(Pasien pasien) {
        data.put(pasien.nama(), pasien);
    }

    public Optional<Pasien> cari(String nama) {
        return Optional.ofNullable(data.get(nama));
    }
}

// ===== Adapter keluar (driven): implementasi B =====
class PenyimpanJejak implements PenyimpanPasien {
    private int jumlah = 0;

    public void simpan(Pasien pasien) {
        jumlah++;
        System.out.println("[AUDIT] simpan #" + jumlah + ": " + pasien.nama());
    }

    public Optional<Pasien> cari(String nama) {
        return Optional.empty(); // jejak audit tidak menyimpan ulang
    }
}
