// Finance app — dashboard, teller, tagihan setup, siswa
function FinanceApp({ ledger, setLedger, view, setView, pushToast }) {
  let body;
  if (view === 'f_dashboard') body = <FinanceDashboard ledger={ledger} setView={setView} />;
  else if (view === 'f_teller') body = <FinanceTeller ledger={ledger} setLedger={setLedger} pushToast={pushToast} />;
  else if (view === 'f_tagihan') body = <FinanceTagihanList ledger={ledger} pushToast={pushToast} />;
  else if (view === 'f_siswa') body = <FinanceSiswa ledger={ledger} />;

  return (
    <div className="app">
      <Sidebar role="finance" view={view} setView={setView} ctx={{}} />
      <div className="main">
        <Topbar>
          <div className="topbar-title">Bagian Keuangan</div>
          <div className="topbar-crumb">/ {NAV_LABEL[view] || ''}</div>
          <div className="topbar-spacer" />
          <div className="row gap-2">
            <div className="badge neutral">TA {SCHOOL.tahunAjaran}</div>
            <button className="btn ghost sm"><Icon name="bell" size={16} /></button>
          </div>
        </Topbar>
        <div className="content">{body}</div>
      </div>
    </div>
  );
}

// ── DASHBOARD ──
function FinanceDashboard({ ledger, setView }) {
  const today = new Date('2026-05-05');
  const totalCollected = ledger.filter(l => l.status === 'lunas').reduce((s, l) => s + l.nominal, 0);
  const totalBilled = ledger.reduce((s, l) => s + l.nominal, 0);
  const overdue = ledger.filter(l => tagihanStatus(l, today) === 'jatuh_tempo');
  const overdueTotal = overdue.reduce((s, l) => s + l.nominal, 0);
  const dueThisWeek = ledger.filter(l => {
    if (l.status === 'lunas') return false;
    const d = new Date(l.jatuhTempo);
    const diff = (d - today) / (24 * 3600 * 1000);
    return diff >= 0 && diff <= 7;
  });

  // Today's payments
  const todayStr = '2026-05-05';
  const todayPayments = ledger.filter(l => l.paidAt === todayStr);

  // Per-class arrears
  const byClass = {};
  ledger.forEach(l => {
    const s = STUDENTS.find(s => s.id === l.siswaId);
    if (!s) return;
    if (!byClass[s.kelas]) byClass[s.kelas] = { total: 0, lunas: 0, count: 0, overdue: 0, students: new Set() };
    byClass[s.kelas].total += l.nominal;
    byClass[s.kelas].count += 1;
    byClass[s.kelas].students.add(s.id);
    if (l.status === 'lunas') byClass[s.kelas].lunas += l.nominal;
    if (tagihanStatus(l, today) === 'jatuh_tempo') byClass[s.kelas].overdue += l.nominal;
  });

  return (
    <>
      <div className="row between mb-4" style={{ alignItems: 'baseline' }}>
        <div>
          <h1>Dashboard Keuangan</h1>
          <p className="lede">Ringkasan tagihan dan pembayaran sekolah hari ini.</p>
        </div>
        <div className="row gap-2">
          <button className="btn outline sm"><Icon name="download" size={14} /> Ekspor Laporan</button>
          <button className="btn sm" onClick={() => setView('f_teller')}>
            <Icon name="cash" size={14} /> Buka Loket
          </button>
        </div>
      </div>

      <div className="stat-grid mb-6">
        <div className="stat">
          <div className="stat-label row gap-2"><Icon name="trendUp" size={14} /> Total Diterima</div>
          <div className="stat-value">{formatRupiahShort(totalCollected)}</div>
          <div className="stat-delta up">{Math.round(totalCollected / totalBilled * 100)}% dari total tagihan</div>
        </div>
        <div className="stat">
          <div className="stat-label row gap-2"><Icon name="alert" size={14} /> Tunggakan</div>
          <div className="stat-value" style={{ color: 'hsl(var(--destructive))' }}>{formatRupiahShort(overdueTotal)}</div>
          <div className="stat-delta">{overdue.length} tagihan dari {new Set(overdue.map(o => o.siswaId)).size} siswa</div>
        </div>
        <div className="stat">
          <div className="stat-label row gap-2"><Icon name="calendar" size={14} /> Jatuh Tempo Minggu Ini</div>
          <div className="stat-value">{dueThisWeek.length}</div>
          <div className="stat-delta">tagihan · {formatRupiahShort(dueThisWeek.reduce((s,l)=>s+l.nominal,0))}</div>
        </div>
        <div className="stat">
          <div className="stat-label row gap-2"><Icon name="cash" size={14} /> Pembayaran Hari Ini</div>
          <div className="stat-value">{todayPayments.length}</div>
          <div className="stat-delta">{formatRupiah(todayPayments.reduce((s,l)=>s+l.nominal,0))}</div>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 20, marginBottom: 24 }}>
        <div className="card">
          <div className="card-header">
            <div>
              <h3 className="card-title">Tunggakan per Kelas</h3>
              <p className="card-desc">Siswa dengan tagihan lewat jatuh tempo</p>
            </div>
          </div>
          <div className="card-body flush">
            <div className="table-wrap">
              <table className="table">
                <thead>
                  <tr>
                    <th>Kelas</th>
                    <th>Siswa</th>
                    <th>Progres Lunas</th>
                    <th className="num">Tunggakan</th>
                  </tr>
                </thead>
                <tbody>
                  {Object.entries(byClass)
                    .filter(([_, v]) => v.overdue > 0)
                    .sort((a, b) => b[1].overdue - a[1].overdue)
                    .map(([kls, v]) => (
                      <tr key={kls}>
                        <td><span style={{ fontWeight: 600 }}>{kls}</span></td>
                        <td className="muted">{v.students.size} siswa</td>
                        <td style={{ width: '40%' }}>
                          <div className="row gap-2">
                            <ProgressBar value={v.lunas} max={v.total} success={v.lunas === v.total} />
                            <span className="text-sm muted tnum" style={{ minWidth: 36, textAlign: 'right' }}>
                              {Math.round(v.lunas / v.total * 100)}%
                            </span>
                          </div>
                        </td>
                        <td className="num tnum" style={{ fontWeight: 600, color: 'hsl(var(--destructive))' }}>
                          {formatRupiah(v.overdue)}
                        </td>
                      </tr>
                    ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-header">
            <div>
              <h3 className="card-title">Aktivitas Loket Hari Ini</h3>
              <p className="card-desc">{formatDateLong(todayStr)}</p>
            </div>
            <button className="btn outline sm" onClick={() => setView('f_teller')}>Lihat Loket</button>
          </div>
          <div className="card-body flush">
            {todayPayments.length === 0 ? (
              <div style={{ padding: 32, textAlign: 'center', color: 'hsl(var(--muted-foreground))' }}>
                <Icon name="cash" size={28} />
                <div style={{ marginTop: 8, fontSize: 13 }}>Belum ada pembayaran hari ini.</div>
                <button className="btn sm mt-4" onClick={() => setView('f_teller')}>Mulai Terima Pembayaran</button>
              </div>
            ) : (
              <div>
                {todayPayments.slice(0, 6).map(l => {
                  const t = TAGIHAN.find(t => t.id === l.tagihanId);
                  const s = STUDENTS.find(s => s.id === l.siswaId);
                  return (
                    <div key={l.id} className="row gap-3" style={{ padding: '10px 20px', borderBottom: '1px solid hsl(var(--border))' }}>
                      <div className="avatar sm" style={{ background: avatarColor(s.nama) }}>{initials(s.nama)}</div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 13, fontWeight: 500 }}>{s.nama.split(' ').slice(0,2).join(' ')}</div>
                        <div className="text-sm muted">{t.nama}</div>
                      </div>
                      <div className="num tnum" style={{ fontWeight: 600, fontSize: 13 }}>{formatRupiah(l.nominal)}</div>
                    </div>
                  );
                })}
              </div>
            )}
          </div>
        </div>
      </div>
    </>
  );
}

// ── TELLER ──
function FinanceTeller({ ledger, setLedger, pushToast }) {
  const [query, setQuery] = React.useState('');
  const [selectedSiswaId, setSelectedSiswaId] = React.useState(null);
  const [confirmRow, setConfirmRow] = React.useState(null);

  const matchingStudents = React.useMemo(() => {
    if (!query.trim()) {
      // top: students with most outstanding
      const out = {};
      ledger.forEach(l => {
        if (l.status !== 'lunas') {
          out[l.siswaId] = (out[l.siswaId] || 0) + 1;
        }
      });
      return STUDENTS
        .filter(s => out[s.id])
        .sort((a, b) => (out[b.id] || 0) - (out[a.id] || 0))
        .slice(0, 8);
    }
    const q = query.toLowerCase();
    return STUDENTS.filter(s =>
      s.nama.toLowerCase().includes(q) ||
      s.nis.includes(q) ||
      s.kelas.toLowerCase().includes(q)
    ).slice(0, 8);
  }, [query, ledger]);

  const selectedSiswa = STUDENTS.find(s => s.id === selectedSiswaId);
  const selectedRows = ledger
    .filter(l => l.siswaId === selectedSiswaId)
    .sort((a, b) => {
      if (a.status === 'lunas' && b.status !== 'lunas') return 1;
      if (a.status !== 'lunas' && b.status === 'lunas') return -1;
      return new Date(a.jatuhTempo) - new Date(b.jatuhTempo);
    });

  const markPaid = (rowId) => {
    setLedger(prev => prev.map(l => {
      if (l.id !== rowId) return l;
      const cnt = prev.filter(p => p.status === 'lunas').length + 1;
      return {
        ...l,
        status: 'lunas',
        paidAt: '2026-05-05',
        paidBy: 'Finance — Ibu Sinta',
        receiptNo: `RCP-${String(cnt).padStart(5, '0')}`,
      };
    }));
    const t = TAGIHAN.find(t => t.id === confirmRow.tagihanId);
    pushToast({ msg: `${t.nama} ditandai lunas`, type: 'success' });
    setConfirmRow(null);
  };

  return (
    <>
      <h1>Loket Pembayaran</h1>
      <p className="lede">Cari siswa, lalu tandai tagihan sebagai lunas saat menerima pembayaran tunai.</p>

      <div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 20 }}>
        <div className="card" style={{ alignSelf: 'start', position: 'sticky', top: 92 }}>
          <div className="card-header">
            <div>
              <h3 className="card-title">Cari Siswa</h3>
              <p className="card-desc">Nama, NIS, atau kelas</p>
            </div>
          </div>
          <div className="card-body" style={{ paddingBottom: 0 }}>
            <div style={{ position: 'relative' }}>
              <Icon name="search" size={14} style={{ position: 'absolute', left: 12, top: 11, color: 'hsl(var(--muted-foreground))' }} />
              <input className="input" placeholder="Ketik nama atau NIS…" value={query}
                     onChange={e => setQuery(e.target.value)} autoFocus
                     style={{ paddingLeft: 34 }} />
            </div>
          </div>
          <div className="card-body flush" style={{ paddingTop: 12 }}>
            <div className="text-sm muted" style={{ padding: '6px 20px 8px' }}>
              {query ? 'Hasil pencarian' : 'Siswa dengan tagihan terbanyak'}
            </div>
            {matchingStudents.map(s => {
              const out = ledger.filter(l => l.siswaId === s.id && l.status !== 'lunas').length;
              const overdue = ledger.filter(l => l.siswaId === s.id && tagihanStatus(l) === 'jatuh_tempo').length;
              const active = s.id === selectedSiswaId;
              return (
                <button key={s.id}
                        className="row gap-3"
                        onClick={() => setSelectedSiswaId(s.id)}
                        style={{
                          width: '100%',
                          padding: '10px 20px',
                          background: active ? 'hsl(var(--accent-h) var(--accent-s) var(--accent-l) / 0.08)' : 'transparent',
                          border: 'none',
                          borderLeft: active ? '3px solid hsl(var(--accent-h) var(--accent-s) var(--accent-l))' : '3px solid transparent',
                          textAlign: 'left',
                          cursor: 'pointer',
                          fontFamily: 'inherit',
                        }}>
                  <div className="avatar sm" style={{ background: avatarColor(s.nama) }}>{initials(s.nama)}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{s.nama}</div>
                    <div className="text-sm muted">{s.kelas} · NIS {s.nis}</div>
                  </div>
                  {overdue > 0 ? (
                    <div className="badge destructive">{overdue}</div>
                  ) : out > 0 ? (
                    <div className="badge accent">{out}</div>
                  ) : (
                    <div className="badge success"><Icon name="check" size={10} /></div>
                  )}
                </button>
              );
            })}
          </div>
        </div>

        <div>
          {!selectedSiswa ? (
            <div className="card" style={{ padding: 60, textAlign: 'center' }}>
              <div style={{
                width: 56, height: 56, borderRadius: 999, background: 'hsl(var(--muted))',
                display: 'grid', placeItems: 'center', margin: '0 auto 12px',
                color: 'hsl(var(--muted-foreground))'
              }}>
                <Icon name="search" size={24} />
              </div>
              <div style={{ fontWeight: 600, fontSize: 15 }}>Pilih siswa untuk memulai</div>
              <div className="text-sm muted" style={{ marginTop: 4 }}>
                Cari di kolom kiri, atau pilih dari daftar siswa dengan tagihan terbanyak.
              </div>
            </div>
          ) : (
            <TellerStudentPanel siswa={selectedSiswa} rows={selectedRows} setConfirmRow={setConfirmRow} />
          )}
        </div>
      </div>

      {confirmRow && (
        <ConfirmPaymentDialog row={confirmRow}
                              onClose={() => setConfirmRow(null)}
                              onConfirm={() => markPaid(confirmRow.id)} />
      )}
    </>
  );
}

function TellerStudentPanel({ siswa, rows, setConfirmRow }) {
  const wali = WALI[siswa.wali];
  const unpaid = rows.filter(r => r.status !== 'lunas');
  const totalUnpaid = unpaid.reduce((s, l) => s + l.nominal, 0);

  return (
    <div className="card">
      <div className="card-header" style={{ paddingBottom: 18, borderBottom: '1px solid hsl(var(--border))' }}>
        <div className="row gap-3">
          <div className="avatar lg" style={{ background: avatarColor(siswa.nama) }}>{initials(siswa.nama)}</div>
          <div>
            <div style={{ fontSize: 18, fontWeight: 600, letterSpacing: '-0.01em' }}>{siswa.nama}</div>
            <div className="text-sm muted">
              Kelas {siswa.kelas} · NIS <span className="mono">{siswa.nis}</span> · Wali: {wali.nama}
            </div>
          </div>
        </div>
        <div style={{ textAlign: 'right' }}>
          <div className="text-sm muted">Total Belum Lunas</div>
          <div style={{ fontSize: 22, fontWeight: 600, fontVariantNumeric: 'tabular-nums', color: unpaid.length ? 'hsl(var(--destructive))' : 'hsl(var(--success))' }}>
            {formatRupiah(totalUnpaid)}
          </div>
        </div>
      </div>

      <div className="card-body flush">
        <div className="table-wrap">
          <table className="table">
            <thead>
              <tr>
                <th>Tagihan</th>
                <th>Jatuh Tempo</th>
                <th>Status</th>
                <th className="num">Nominal</th>
                <th className="actions">Aksi</th>
              </tr>
            </thead>
            <tbody>
              {rows.map(l => {
                const t = TAGIHAN.find(t => t.id === l.tagihanId);
                const status = tagihanStatus(l);
                const bt = BILL_TYPES[t.tipe];
                return (
                  <tr key={l.id}>
                    <td>
                      <div className="row gap-2">
                        <div style={{
                          width: 30, height: 30, borderRadius: 6,
                          background: 'hsl(var(--accent-h) var(--accent-s) 95%)',
                          color: 'hsl(var(--accent-h) var(--accent-s) 35%)',
                          display: 'grid', placeItems: 'center',
                        }}>
                          <Icon name={bt.icon} size={14} />
                        </div>
                        <div>
                          <div style={{ fontWeight: 500 }}>{t.nama}</div>
                          <div className="text-sm muted">{bt.label}</div>
                        </div>
                      </div>
                    </td>
                    <td className="tnum">{formatDate(l.jatuhTempo)}</td>
                    <td><StatusBadge status={status} /></td>
                    <td className="num tnum" style={{ fontWeight: 600 }}>{formatRupiah(l.nominal)}</td>
                    <td className="actions">
                      {l.status === 'lunas' ? (
                        <span className="text-sm muted mono">{l.receiptNo}</span>
                      ) : (
                        <button className="btn sm" onClick={() => setConfirmRow(l)}>
                          <Icon name="check" size={13} /> Tandai Lunas
                        </button>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

function ConfirmPaymentDialog({ row, onClose, onConfirm }) {
  const t = TAGIHAN.find(t => t.id === row.tagihanId);
  const s = STUDENTS.find(s => s.id === row.siswaId);
  const w = WALI[s.wali];
  const [received, setReceived] = React.useState(row.nominal);
  const change = received - row.nominal;

  return (
    <div className="dialog-backdrop" onClick={onClose}>
      <div className="dialog" onClick={e => e.stopPropagation()}>
        <div className="dialog-header">
          <div className="dialog-title">Konfirmasi Pembayaran</div>
          <div className="dialog-desc">Pastikan jumlah yang diterima sudah sesuai sebelum menandai lunas.</div>
        </div>
        <div className="dialog-body">
          <div className="receipt mb-4">
            <div className="receipt-line"><span className="muted">Siswa</span><span style={{ fontWeight: 500 }}>{s.nama} ({s.kelas})</span></div>
            <div className="receipt-line"><span className="muted">Wali</span><span>{w.nama}</span></div>
            <div className="receipt-line"><span className="muted">Tagihan</span><span style={{ fontWeight: 500 }}>{t.nama}</span></div>
            <div className="receipt-line total"><span>Jumlah Tagihan</span><span className="tnum">{formatRupiah(row.nominal)}</span></div>
          </div>

          <div className="field mb-4">
            <label>Jumlah uang diterima</label>
            <input className="input tnum" type="number" value={received}
                   onChange={e => setReceived(Number(e.target.value))} />
            {change !== 0 && (
              <div className="field-help" style={{ color: change < 0 ? 'hsl(var(--destructive))' : 'hsl(var(--success))' }}>
                {change < 0 ? `Kurang ${formatRupiah(-change)}` : `Kembalian ${formatRupiah(change)}`}
              </div>
            )}
          </div>

          <div className="field">
            <label>Catatan (opsional)</label>
            <textarea className="textarea" placeholder="Misal: dibayar oleh kakak siswa…"></textarea>
          </div>
        </div>
        <div className="dialog-footer">
          <button className="btn outline" onClick={onClose}>Batal</button>
          <button className="btn" disabled={received < row.nominal} onClick={onConfirm}>
            <Icon name="check" size={14} /> Tandai Lunas & Cetak Kuitansi
          </button>
        </div>
      </div>
    </div>
  );
}

// ── TAGIHAN LIST (define who pays) ──
function FinanceTagihanList({ ledger, pushToast }) {
  const [openCreate, setOpenCreate] = React.useState(false);

  return (
    <>
      <div className="row between mb-4" style={{ alignItems: 'baseline' }}>
        <div>
          <h1>Daftar Tagihan</h1>
          <p className="lede">Definisikan tagihan dan tentukan siswa mana yang harus membayar.</p>
        </div>
        <button className="btn" onClick={() => setOpenCreate(true)}>
          <Icon name="plus" size={14} /> Buat Tagihan Baru
        </button>
      </div>

      <div className="card">
        <div className="card-body flush">
          <div className="table-wrap">
            <table className="table">
              <thead>
                <tr>
                  <th>Tagihan</th>
                  <th>Sasaran</th>
                  <th>Jatuh Tempo</th>
                  <th className="num">Nominal</th>
                  <th>Progres</th>
                  <th className="num">Terkumpul</th>
                  <th className="actions"></th>
                </tr>
              </thead>
              <tbody>
                {TAGIHAN.map(t => {
                  const rows = ledger.filter(l => l.tagihanId === t.id);
                  const lunas = rows.filter(l => l.status === 'lunas').length;
                  const totalCollected = rows.filter(l => l.status === 'lunas').reduce((s,l)=>s+l.nominal,0);
                  const totalBilled = rows.reduce((s,l)=>s+l.nominal,0);
                  const bt = BILL_TYPES[t.tipe];
                  return (
                    <tr key={t.id}>
                      <td>
                        <div className="row gap-2">
                          <div style={{
                            width: 32, height: 32, borderRadius: 6,
                            background: 'hsl(var(--accent-h) var(--accent-s) 95%)',
                            color: 'hsl(var(--accent-h) var(--accent-s) 32%)',
                            display: 'grid', placeItems: 'center',
                          }}>
                            <Icon name={bt.icon} size={14} />
                          </div>
                          <div>
                            <div style={{ fontWeight: 500 }}>{t.nama}</div>
                            <div className="text-sm muted">{bt.label} · <span className="mono">{t.id}</span></div>
                          </div>
                        </div>
                      </td>
                      <td>
                        {t.target === 'all'
                          ? <span className="badge neutral">Seluruh siswa · {rows.length}</span>
                          : <span className="badge accent">Kelas {t.kelas.join(', ')} · {rows.length}</span>}
                      </td>
                      <td className="tnum">{formatDate(t.jatuhTempo)}</td>
                      <td className="num tnum" style={{ fontWeight: 600 }}>{formatRupiah(t.nominal)}</td>
                      <td style={{ width: 180 }}>
                        <div className="row gap-2">
                          <ProgressBar value={lunas} max={rows.length} success={lunas === rows.length} />
                          <span className="text-sm muted tnum" style={{ minWidth: 56, textAlign: 'right' }}>{lunas}/{rows.length}</span>
                        </div>
                      </td>
                      <td className="num tnum" style={{ fontWeight: 500 }}>{formatRupiahShort(totalCollected)}</td>
                      <td className="actions">
                        <button className="btn ghost sm"><Icon name="more" size={14} /></button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      </div>

      {openCreate && <CreateTagihanDialog onClose={() => setOpenCreate(false)} pushToast={pushToast} />}
    </>
  );
}

function CreateTagihanDialog({ onClose, pushToast }) {
  const [tipe, setTipe] = React.useState('spp');
  const [nama, setNama] = React.useState('');
  const [nominal, setNominal] = React.useState(350000);
  const [target, setTarget] = React.useState('all');
  const [selectedKelas, setSelectedKelas] = React.useState(['4A']);
  const [jatuhTempo, setJatuhTempo] = React.useState('2026-06-10');

  const targetCount = target === 'all'
    ? STUDENTS.length
    : STUDENTS.filter(s => selectedKelas.includes(s.kelas)).length;

  const submit = () => {
    pushToast({ msg: `Tagihan "${nama || BILL_TYPES[tipe].label}" dibuat untuk ${targetCount} siswa`, type: 'success' });
    onClose();
  };

  return (
    <div className="dialog-backdrop" onClick={onClose}>
      <div className="dialog" onClick={e => e.stopPropagation()} style={{ maxWidth: 580 }}>
        <div className="dialog-header">
          <div className="dialog-title">Buat Tagihan Baru</div>
          <div className="dialog-desc">Tentukan jenis tagihan, nominal, dan siswa mana yang harus membayar.</div>
        </div>
        <div className="dialog-body">
          <div className="col gap-4">
            <div className="field">
              <label>Jenis Tagihan</label>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
                {Object.entries(BILL_TYPES).map(([k, v]) => (
                  <button key={k}
                          onClick={() => setTipe(k)}
                          style={{
                            padding: '12px 10px',
                            borderRadius: 8,
                            border: '1px solid ' + (tipe === k ? 'hsl(var(--accent-h) var(--accent-s) var(--accent-l))' : 'hsl(var(--border))'),
                            background: tipe === k ? 'hsl(var(--accent-h) var(--accent-s) var(--accent-l) / 0.06)' : 'white',
                            display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 6,
                            cursor: 'pointer',
                            fontFamily: 'inherit',
                          }}>
                    <Icon name={v.icon} size={16} style={{ color: 'hsl(var(--accent-h) var(--accent-s) var(--accent-l))' }} />
                    <span style={{ fontSize: 12.5, fontWeight: 500 }}>{v.label}</span>
                  </button>
                ))}
              </div>
            </div>

            <div className="field">
              <label>Nama Tagihan</label>
              <input className="input" placeholder={`Contoh: ${BILL_TYPES[tipe].label} Juni 2026`}
                     value={nama} onChange={e => setNama(e.target.value)} />
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              <div className="field">
                <label>Nominal</label>
                <input className="input tnum" type="number" value={nominal}
                       onChange={e => setNominal(Number(e.target.value))} />
                <div className="field-help">{formatRupiah(nominal)}</div>
              </div>
              <div className="field">
                <label>Jatuh Tempo</label>
                <input className="input" type="date" value={jatuhTempo}
                       onChange={e => setJatuhTempo(e.target.value)} />
              </div>
            </div>

            <div className="field">
              <label>Sasaran Siswa</label>
              <div className="tabs" style={{ alignSelf: 'flex-start' }}>
                <button className={`tab ${target === 'all' ? 'active' : ''}`} onClick={() => setTarget('all')}>Seluruh sekolah</button>
                <button className={`tab ${target === 'kelas' ? 'active' : ''}`} onClick={() => setTarget('kelas')}>Pilih kelas</button>
              </div>
              {target === 'kelas' && (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 8 }}>
                  {KELAS.map(k => {
                    const sel = selectedKelas.includes(k);
                    return (
                      <button key={k}
                              onClick={() => setSelectedKelas(prev => sel ? prev.filter(x => x !== k) : [...prev, k])}
                              className={`badge ${sel ? 'accent' : 'neutral'}`}
                              style={{ cursor: 'pointer', border: 'none', padding: '6px 12px', fontSize: 12 }}>
                        {sel && <Icon name="check" size={11} />} {k}
                      </button>
                    );
                  })}
                </div>
              )}
              <div className="field-help">
                Tagihan akan dibuat untuk <strong>{targetCount} siswa</strong>.
                Total potensi: <strong className="tnum">{formatRupiah(targetCount * nominal)}</strong>.
              </div>
            </div>
          </div>
        </div>
        <div className="dialog-footer">
          <button className="btn outline" onClick={onClose}>Batal</button>
          <button className="btn" onClick={submit}>
            <Icon name="check" size={14} /> Buat Tagihan
          </button>
        </div>
      </div>
    </div>
  );
}

// ── SISWA & WALI ──
function FinanceSiswa({ ledger }) {
  const [query, setQuery] = React.useState('');
  const [kelas, setKelas] = React.useState('all');

  const filtered = STUDENTS.filter(s => {
    if (kelas !== 'all' && s.kelas !== kelas) return false;
    if (query.trim()) {
      const q = query.toLowerCase();
      return s.nama.toLowerCase().includes(q) || s.nis.includes(q);
    }
    return true;
  });

  return (
    <>
      <h1>Siswa & Wali</h1>
      <p className="lede">Daftar siswa dengan ringkasan tunggakan masing-masing.</p>

      <div className="row gap-2 mb-4">
        <div style={{ position: 'relative', flex: 1, maxWidth: 360 }}>
          <Icon name="search" size={14} style={{ position: 'absolute', left: 12, top: 11, color: 'hsl(var(--muted-foreground))' }} />
          <input className="input" placeholder="Cari nama atau NIS…" value={query}
                 onChange={e => setQuery(e.target.value)} style={{ paddingLeft: 34 }} />
        </div>
        <select className="select" value={kelas} onChange={e => setKelas(e.target.value)} style={{ width: 160 }}>
          <option value="all">Semua kelas</option>
          {KELAS.map(k => <option key={k} value={k}>Kelas {k}</option>)}
        </select>
      </div>

      <div className="card">
        <div className="card-body flush">
          <div className="table-wrap">
            <table className="table">
              <thead>
                <tr>
                  <th>Siswa</th>
                  <th>Kelas</th>
                  <th>Wali Murid</th>
                  <th>Status</th>
                  <th className="num">Tunggakan</th>
                  <th className="actions"></th>
                </tr>
              </thead>
              <tbody>
                {filtered.map(s => {
                  const rows = ledger.filter(l => l.siswaId === s.id);
                  const overdueAmt = rows.filter(l => tagihanStatus(l) === 'jatuh_tempo').reduce((sum,l)=>sum+l.nominal,0);
                  const unpaidCount = rows.filter(l => l.status !== 'lunas').length;
                  const w = WALI[s.wali];
                  return (
                    <tr key={s.id}>
                      <td>
                        <div className="row gap-2">
                          <div className="avatar sm" style={{ background: avatarColor(s.nama) }}>{initials(s.nama)}</div>
                          <div>
                            <div style={{ fontWeight: 500 }}>{s.nama}</div>
                            <div className="text-sm muted mono">NIS {s.nis}</div>
                          </div>
                        </div>
                      </td>
                      <td>{s.kelas}</td>
                      <td>
                        <div>{w.nama}</div>
                        <div className="text-sm muted mono">{w.hp}</div>
                      </td>
                      <td>
                        {overdueAmt > 0 ? <span className="badge destructive dot">Tertunggak</span> :
                         unpaidCount > 0 ? <span className="badge warning dot">{unpaidCount} belum bayar</span> :
                         <span className="badge success dot">Lunas semua</span>}
                      </td>
                      <td className="num tnum" style={{ fontWeight: 600, color: overdueAmt > 0 ? 'hsl(var(--destructive))' : 'inherit' }}>
                        {overdueAmt > 0 ? formatRupiah(overdueAmt) : '—'}
                      </td>
                      <td className="actions">
                        <button className="btn ghost sm"><Icon name="more" size={14} /></button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </>
  );
}

window.FinanceApp = FinanceApp;
