"""Sesi 16 — Final Project Development | Kode Pendamping Lengkap
SMAS St. John · Ekskul CSSE (Python)

Kerangka aplikasi Final Project UTUH yang bisa langsung dijalankan:
"APLIKASI PENGELOLA DATA BERBASIS MENU + FILE (CLI)".
Domain contoh: Sistem Nilai Siswa (default) — 4 domain lain
(Perpustakaan, Kasir, Kontak, Todo) memakai mesin yang sama persis,
tinggal ganti field dict-nya.

Cara pakai:
  1. Simpan file ini, buka di VS Code
  2. Tekan Run ▶ (atau ketik di terminal: python kode.py)
  3. Coba semua menu: tambah data, lihat, cari, hapus, statistik
  4. Tutup program, jalankan lagi — data masih ada (bukti file bekerja)
  5. Baca komentar di dalamnya: setiap BAGIAN sesuai urutan deck Sesi 16

File ini mengikuti alur deck:
  BAGIAN 1 = data & konstanta             (slide 09)
  BAGIAN 2 = file I/O: load & save        (slide 10)
  BAGIAN 3 = fitur: lihat & tambah        (slide 11-12)
  BAGIAN 4 = fitur: cari & hapus          (slide 12)
  BAGIAN 5 = fitur: statistik             (slide 12-13)
  BAGIAN 6 = program utama (menu loop)    (slide 07)
  BAGIAN 7 = challenge: stretch level A   (slide 14-15)
"""

# ============================================================
# BAGIAN 1 — data & konstanta (slide 09)
# ============================================================
# data = SATU-SATUNYA sumber kebenaran. Semua fungsi membaca atau
# mengubahnya. 1 dict = 1 catatan (siswa/buku/barang/konten/tugas).

FILE = "data.txt"
data = []   # list[dict] — contoh: [{"nama": "Budi", "nilai": 85}]

# Ganti domain? Ubah field dict di BAGIAN 3-4 saja:
#   Perpustakaan : {"judul": "...", "penulis": "...", "status": "tersedia"}
#   Kasir Warung : {"barang": "...", "harga": 5000, "stok": 12}
#   Kontak       : {"nama": "...", "hp": "...", "email": "..."}
#   Todo/Agenda  : {"tugas": "...", "deadline": "...", "status": "belum"}

# ============================================================
# BAGIAN 2 — file I/O: load & save (slide 10)
# ============================================================
# Kontraknya cuma DUA:
#   load_file()   -> dipanggil SEKALI di awal program
#   simpan_file() -> dipanggil SETIAP KALI data berubah
# Lupa salah satu = data palsu di sesi berikutnya!

def simpan_file():
    # "w" = write (tulis ulang dari awal) — data.txt tercipta otomatis
    with open(FILE, "w", encoding="utf-8") as f:
        for item in data:
            f.write(f"{item['nama']},{item['nilai']}\n")

def load_file():
    # "r" = read — baca baris per baris lewat readlines()
    try:
        with open(FILE, "r", encoding="utf-8") as f:
            for baris in f.readlines():
                baris = baris.strip()          # buang enter di ujung
                if baris == "":                # baris kosong -> lewati
                    continue
                nama, nilai = baris.split(",") # "Budi,85" -> dua potong
                data.append({"nama": nama, "nilai": int(nilai)})
    except FileNotFoundError:
        # run pertama: file belum ada — bukan error, mulai kosong
        print("File belum ada - mulai dengan data kosong.")

# ============================================================
# BAGIAN 3 — fitur: lihat & tambah (slide 11-12)
# ============================================================

def tampilkan_data():
    if len(data) == 0:
        print("Belum ada data.")
        return
    for i, item in enumerate(data, start=1):
        if item["nilai"] >= 75:
            status = "Lulus"
        else:
            status = "Remedial"
        print(f"{i}. {item['nama']} - nilai {item['nilai']} ({status})")

def tambah_data():
    nama = input("Nama: ")
    # pola while True + try-except: tanya berulang sampai input sah.
    # Satu huruf nakal tidak boleh menjatuhkan aplikasi!
    while True:
        try:
            nilai = int(input("Nilai (0-100): "))
            break
        except ValueError:
            print("Harus angka! Contoh: 85")
    data.append({"nama": nama, "nilai": nilai})
    simpan_file()   # kontrak: data berubah = WAJIB save
    print(f"Data {nama} ditambahkan.")
# Output:
# Nama: Budi
# Nilai (0-100): lima
# Harus angka! Contoh: 85
# Nilai (0-100): 85
# Data Budi ditambahkan.

# ============================================================
# BAGIAN 4 — fitur: cari & hapus (slide 12)
# ============================================================

def cari_data(kata):
    # .lower() di dua sisi -> "budi" ketemu "Budi" (case-insensitive)
    hasil = []
    for item in data:
        if kata.lower() in item["nama"].lower():
            hasil.append(item)
    return hasil   # bisa kosong — penelepon yang memutuskan pesannya

def hapus_data():
    kata = input("Nama yang dihapus: ")
    ketemu = None
    for i, item in enumerate(data):
        if item["nama"].lower() == kata.lower():
            ketemu = i
            break
    if ketemu is None:
        print(f"Data '{kata}' tidak ditemukan.")   # pesan jujur, bukan crash
    else:
        del data[ketemu]
        simpan_file()   # kontrak: data berubah = WAJIB save
        print(f"Data '{kata}' dihapus.")

# JEBAKAN (jangan di-run) — kunci dict harus PERSIS:
# print(item["Nama"])    # KeyError! kuncinya "nama" (huruf kecil)
# print(item["niali"])   # KeyError! typo
# Pilih nama field sekali di awal, tulis konsisten — snake_case semua.

# ============================================================
# BAGIAN 5 — fitur: statistik (slide 12-13)
# ============================================================

def statistik():
    if len(data) == 0:
        print("Belum ada data untuk dihitung.")
        return
    nilai = [item["nilai"] for item in data]
    rata = sum(nilai) / len(nilai)   # pola rata-rata dari Sesi 09!
    print(f"Jumlah data     : {len(nilai)}")
    print(f"Nilai tertinggi : {max(nilai)}")
    print(f"Nilai terendah  : {min(nilai)}")
    print(f"Rata-rata       : {rata:.1f}")
# Output (dengan data Budi 85, Sari 72):
# Jumlah data     : 2
# Nilai tertinggi : 85
# Nilai terendah  : 72
# Rata-rata       : 78.5

# ============================================================
# BAGIAN 6 — program utama: menu loop (slide 07)
# ============================================================
# Semua def WAJIB di atas loop — Python baca atas-ke-bawah.
# Fungsi dipanggil sebelum didefinisikan = NameError.

load_file()   # kontrak: load SEKALI, sebelum loop menu

while True:
    print("\n=== APLIKASI NILAI SISWA ===")
    print("1. Lihat  2. Tambah  3. Cari  4. Hapus  5. Statistik  6. Keluar")
    pilihan = input("Pilih menu (1-6): ")
    if pilihan == "1":
        tampilkan_data()
    elif pilihan == "2":
        tambah_data()
    elif pilihan == "3":
        kata = input("Cari nama: ")
        hasil = cari_data(kata)
        if len(hasil) == 0:
            print(f"Tidak ada data dengan nama '{kata}'.")
        else:
            for item in hasil:
                print(f"Ketemu: {item['nama']} - {item['nilai']}")
    elif pilihan == "4":
        hapus_data()
    elif pilihan == "5":
        statistik()
    elif pilihan == "6":
        simpan_file()   # jaring pengaman terakhir sebelum keluar
        print("Sampai jumpa!")
        break
    else:
        print("Menu 1-6 saja!")
# Output saat pilih 6:
# Sampai jumpa!
# (jalankan lagi -> data masih ada — bukti file bekerja)

# JEBAKAN (jangan di-run) — perbandingan salah tipe:
# if pilihan == 6:        # input() menghasilkan STRING "6", bukan angka!
#     ...                 # cabang ini TIDAK PERNAH jalan -> menu tidak berhenti
# Solusinya: bandingkan string dengan string (== "6") — konsisten.

# ============================================================
# BAGIAN 7 — Challenge: stretch level A (slide 14-15)
# ============================================================
# Kerjakan SETELAH baseline B aman & self-test lolos semua.
# Lepas tanda # untuk mencoba — atau tulis ulang versi sendiri.

# STRETCH 1 — sort nilai tertinggi dulu (menu tampilan tambahan):
# urut = sorted(data, key=lambda item: item["nilai"], reverse=True)
# for item in urut:
#     print(item["nama"], item["nilai"])
# Output: Rina 90 -> Budi 85 -> Sari 72

# STRETCH 2 — edit/update nilai (1 menu = 1 fungsi, seperti biasa):
# def edit_data():
#     kata = input("Nama yang diedit: ")
#     for item in data:
#         if item["nama"].lower() == kata.lower():
#             item["nilai"] = int(input("Nilai baru: "))
#             simpan_file()   # edit = data berubah = WAJIB save
#             print("Data diperbarui.")
#             return          # berhenti — pesan "tidak ketemu" tidak ikut
#     print(f"Data '{kata}' tidak ditemukan.")

# STRETCH 3 — laporan otomatis ke file terpisah:
# def laporan_ke_file():
#     nilai = [item["nilai"] for item in data]
#     with open("laporan.txt", "w", encoding="utf-8") as f:
#         f.write(f"LAPORAN NILAI SISWA\n")
#         f.write(f"Jumlah data : {len(nilai)}\n")
#         if len(nilai) > 0:
#             f.write(f"Rata-rata   : {sum(nilai) / len(nilai):.1f}\n")
#     print("Laporan tersimpan ke laporan.txt")

# ============================================================
# Checklist rubrik (cek sebelum pulang — dan sebelum Sesi 17)
# ============================================================
# [ ] Menu while True jalan: 5 opsi + Keluar, bolak-balik tanpa crash
# [ ] Data di list[dict], akses pakai kunci yang konsisten
# [ ] Modular: 1 menu = 1 fungsi (7 fungsi di atas)
# [ ] load_file() sekali di awal, simpan_file() tiap perubahan
# [ ] try-except: ValueError (input angka) + FileNotFoundError (file)
# [ ] Self-test lolos: huruf di kolom angka, cari/hapus tidak ada,
#     hapus list kosong, tutup-buka program -> data masih ada
# [ ] Sudah pilih 1 fungsi yang akan dibanggakan di Demo Day
