/* global React, Icon, fmtRp */
const { useState: useStateAcc, useEffect: useEffectAcc, useMemo: useMemoAcc } = React;

const TYPE_LABEL = {
  asset:     { label:'Aset',       color:'var(--brand-500)' },
  liability: { label:'Liabilitas', color:'var(--amber)' },
  equity:    { label:'Ekuitas',    color:'var(--blue)' },
  revenue:   { label:'Pendapatan', color:'var(--green)' },
  expense:   { label:'Beban',      color:'var(--rose)' },
};

/* =========================================================
 * AKUN PERKIRAAN (Chart of Accounts)
 * ========================================================= */
function AccountsPage() {
  const [accounts, setAccounts] = useStateAcc([]);
  const [loading, setLoading] = useStateAcc(true);
  const [filter, setFilter] = useStateAcc('');
  const [createOpen, setCreateOpen] = useStateAcc(false);
  const [openLedger, setOpenLedger] = useStateAcc(null);

  const load = async () => {
    setLoading(true);
    try {
      const r = await window.Api.get('/api/accounts');
      setAccounts(r.data || []);
    } finally { setLoading(false); }
  };
  useEffectAcc(() => { load(); }, []);

  const filtered = useMemoAcc(() => {
    if (!filter) return accounts;
    return accounts.filter((a) => a.type === filter);
  }, [accounts, filter]);

  const seedCOA = async () => {
    if (!confirm('Buat 48 akun standar (COA Indonesia)?')) return;
    try {
      await window.Api.post('/api/accounts/seed', {});
      await load();
    } catch (e) { alert(e.message); }
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Akun Perkiraan</h1>
          <p className="page-sub">Daftar akun (chart of accounts) yang dipakai untuk jurnal & laporan keuangan</p>
        </div>
        <div className="page-actions">
          {accounts.length === 0 && (
            <button className="btn btn-secondary" onClick={seedCOA}><Icon.zap/> Seed COA Default</button>
          )}
          <button className="btn btn-secondary"><Icon.download/> Ekspor</button>
          <button className="btn btn-primary" onClick={() => setCreateOpen(true)}><Icon.plus/> Akun Baru</button>
        </div>
      </div>

      <div className="grid-4" style={{ marginBottom:18 }}>
        {Object.entries(TYPE_LABEL).map(([k, v]) => (
          <SmallStatAcc
            key={k}
            label={v.label}
            value={accounts.filter((a) => a.type === k && !a.isHeader).length}
            tone={k}
            active={filter === k}
            onClick={() => setFilter(filter === k ? '' : k)}
          />
        ))}
      </div>

      <div className="card" style={{ overflow:'hidden' }}>
        {loading && <div style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Memuat…</div>}
        {!loading && (
          <table className="table">
            <thead>
              <tr>
                <th style={{ width:90 }}>Kode</th>
                <th>Nama</th>
                <th>Tipe</th>
                <th>Sub-tipe</th>
                <th style={{ textAlign:'right' }}>Saldo</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {filtered.length === 0 && (
                <tr><td colSpan="6" style={{ padding:'40px 24px', textAlign:'center', color:'var(--ink-500)' }}>
                  Belum ada akun. Klik <strong>Seed COA Default</strong> untuk pakai struktur standar.
                </td></tr>
              )}
              {filtered.map((a) => {
                const meta = TYPE_LABEL[a.type];
                const indent = a.code.length >= 4 && a.parentId ? 16 : 0;
                return (
                  <tr key={a.id} style={{ background: a.isHeader ? 'var(--surface-2)' : 'transparent' }}>
                    <td>
                      <span className="mono" style={{
                        fontWeight: a.isHeader ? 800 : 600,
                        paddingLeft: indent,
                      }}>{a.code}</span>
                    </td>
                    <td style={{
                      fontWeight: a.isHeader ? 700 : 500,
                      color: a.isHeader ? meta.color : 'var(--ink-900)',
                      textTransform: a.isHeader ? 'uppercase' : 'none',
                      fontSize: a.isHeader ? 12 : 14,
                      letterSpacing: a.isHeader ? '.04em' : 'normal',
                    }}>{a.name}</td>
                    <td><span className="chip" style={{ background:`${meta.color}1a`, color: meta.color }}>{meta.label}</span></td>
                    <td style={{ fontSize:12, color:'var(--ink-500)' }}>{a.subtype}</td>
                    <td style={{
                      textAlign:'right',
                      fontWeight: a.isHeader ? 700 : 500,
                      fontFeatureSettings:'"tnum"',
                      color: a.balance < 0 ? 'var(--rose)' : 'inherit',
                    }}>{a.isHeader ? '' : fmtRp(a.balance)}</td>
                    <td style={{ textAlign:'right' }}>
                      {!a.isHeader && (
                        <button className="btn btn-secondary btn-sm" onClick={() => setOpenLedger(a)}>
                          Buku Besar
                        </button>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>

      {createOpen && <CreateAccountModal accounts={accounts} onClose={() => setCreateOpen(false)} onCreated={load}/>}
      {openLedger && <LedgerModal account={openLedger} onClose={() => setOpenLedger(null)}/>}
    </div>
  );
}

function CreateAccountModal({ accounts, onClose, onCreated }) {
  const [code, setCode] = useStateAcc('');
  const [name, setName] = useStateAcc('');
  const [type, setType] = useStateAcc('asset');
  const [subtype, setSubtype] = useStateAcc('cash');
  const [parentId, setParentId] = useStateAcc('');
  const [busy, setBusy] = useStateAcc(false);
  const [error, setError] = useStateAcc('');

  const SUBTYPES = {
    asset:     ['cash','bank','ar','inventory','fixed_asset','other_asset'],
    liability: ['ap','tax','accrued','loan','unearned','other_liability'],
    equity:    ['capital','retained_earnings','period_earnings'],
    revenue:   ['sales','discount','returns_allowance','other_income'],
    expense:   ['cogs','opex','tax_expense','other_expense'],
  };

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    setBusy(true);
    try {
      await window.Api.post('/api/accounts', {
        code, name, type, subtype,
        parentId: parentId || undefined,
      });
      await onCreated();
      onClose();
    } catch (err) {
      setError(err.message || 'Gagal');
      setBusy(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth: 540 }} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <h2 style={{ margin:0, fontSize:20, fontWeight:800 }}>Akun Baru</h2>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <form onSubmit={submit} style={{ padding:'20px 22px', display:'flex', flexDirection:'column', gap:14 }}>
          {error && <div style={{ padding:'10px 14px', background:'#fee2e2', color:'#991b1b', borderRadius:8, fontSize:13 }}>{error}</div>}
          <div style={{ display:'grid', gridTemplateColumns:'1fr 2fr', gap:12 }}>
            <FieldAcc label="Kode">
              <input className="input" value={code} onChange={e=>setCode(e.target.value)} placeholder="1180" required/>
            </FieldAcc>
            <FieldAcc label="Nama">
              <input className="input" value={name} onChange={e=>setName(e.target.value)} placeholder="Bank Lainnya" required/>
            </FieldAcc>
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12 }}>
            <FieldAcc label="Tipe">
              <select className="input" value={type} onChange={e => { setType(e.target.value); setSubtype(SUBTYPES[e.target.value][0]); }}>
                {Object.entries(TYPE_LABEL).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
              </select>
            </FieldAcc>
            <FieldAcc label="Sub-tipe">
              <select className="input" value={subtype} onChange={e=>setSubtype(e.target.value)}>
                {SUBTYPES[type].map(s => <option key={s} value={s}>{s}</option>)}
              </select>
            </FieldAcc>
          </div>
          <FieldAcc label="Akun induk (opsional)">
            <select className="input" value={parentId} onChange={e=>setParentId(e.target.value)}>
              <option value="">— Tidak ada —</option>
              {accounts.filter(a => a.isHeader && a.type === type).map(a => (
                <option key={a.id} value={a.id}>{a.code} {a.name}</option>
              ))}
            </select>
          </FieldAcc>
          <div className="modal-foot" style={{ margin:'4px -22px -20px' }}>
            <button type="button" className="btn btn-secondary" onClick={onClose} disabled={busy}>Batal</button>
            <button type="submit" className="btn btn-primary" disabled={busy}>{busy ? 'Menyimpan…' : 'Simpan'}</button>
          </div>
        </form>
      </div>
    </div>
  );
}

function LedgerModal({ account, onClose }) {
  const [data, setData] = useStateAcc(null);
  const [from, setFrom] = useStateAcc('');
  const [to, setTo] = useStateAcc('');

  const load = async () => {
    const q = new URLSearchParams();
    if (from) q.set('from', from);
    if (to) q.set('to', to);
    const r = await window.Api.get(`/api/accounts/${account.id}/ledger?${q.toString()}`);
    setData(r.data);
  };
  useEffectAcc(() => { load(); /* eslint-disable-next-line */ }, [from, to]);

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:920, maxHeight:'90vh', display:'flex', flexDirection:'column' }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'.06em', color:'var(--ink-500)' }}>
              Buku Besar
            </div>
            <h2 style={{ margin:'4px 0 0', fontSize:20, fontWeight:800 }}>
              <span className="mono" style={{ fontWeight:700, opacity:.6, marginRight:8 }}>{account.code}</span>
              {account.name}
            </h2>
          </div>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <div style={{ padding:'14px 22px', borderBottom:'1px solid var(--border)', display:'flex', alignItems:'center', gap:14 }}>
          <window.DateRangeFilter from={from} to={to} onChange={({ from, to }) => { setFrom(from); setTo(to); }}/>
          {data && (
            <div style={{ marginLeft:'auto', display:'flex', gap:18, fontSize:12 }}>
              <div><span style={{ color:'var(--ink-500)' }}>Saldo Awal:</span> <strong>{fmtRp(data.openingBalance)}</strong></div>
              <div><span style={{ color:'var(--ink-500)' }}>Saldo Akhir:</span> <strong style={{ color:'var(--brand-600)' }}>{fmtRp(data.closingBalance)}</strong></div>
            </div>
          )}
        </div>
        <div style={{ overflow:'auto', flex:1 }}>
          <table className="table">
            <thead style={{ position:'sticky', top:0, background:'var(--surface)' }}>
              <tr>
                <th>Tanggal</th>
                <th>No. Jurnal</th>
                <th>Keterangan</th>
                <th style={{ textAlign:'right' }}>Debit</th>
                <th style={{ textAlign:'right' }}>Kredit</th>
                <th style={{ textAlign:'right' }}>Saldo</th>
              </tr>
            </thead>
            <tbody>
              {!data && <tr><td colSpan="6" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Memuat…</td></tr>}
              {data && data.lines.length === 0 && (
                <tr><td colSpan="6" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>
                  Belum ada transaksi pada akun ini di rentang tanggal terpilih.
                </td></tr>
              )}
              {data && data.lines.map(l => (
                <tr key={l.lineId}>
                  <td>{l.entryDate}</td>
                  <td><span className="mono" style={{ fontSize:12 }}>{l.entryId}</span></td>
                  <td>
                    <div>{l.description}</div>
                    {l.memo && <div style={{ fontSize:11, color:'var(--ink-500)' }}>{l.memo}</div>}
                  </td>
                  <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"' }}>{Number(l.debit) ? fmtRp(Number(l.debit)) : '—'}</td>
                  <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"' }}>{Number(l.credit) ? fmtRp(Number(l.credit)) : '—'}</td>
                  <td style={{ textAlign:'right', fontWeight:600, fontFeatureSettings:'"tnum"' }}>{fmtRp(l.runningBalance)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

/* =========================================================
 * JURNAL UMUM
 * ========================================================= */
function JournalsPage() {
  const [list, setList] = useStateAcc([]);
  const [loading, setLoading] = useStateAcc(true);
  const [createOpen, setCreateOpen] = useStateAcc(false);
  const [openId, setOpen] = useStateAcc(null);
  const [from, setFrom] = useStateAcc('');
  const [to, setTo] = useStateAcc('');

  const load = async () => {
    setLoading(true);
    const q = new URLSearchParams();
    if (from) q.set('from', from);
    if (to) q.set('to', to);
    const r = await window.Api.get(`/api/journals?${q.toString()}`);
    setList(r.data || []);
    setLoading(false);
  };
  useEffectAcc(() => { load(); /* eslint-disable-next-line */ }, [from, to]);

  const counts = list.reduce((a, e) => { a[e.status] = (a[e.status]||0)+1; return a; }, {});

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Jurnal Umum</h1>
          <p className="page-sub">Catatan transaksi double-entry. Setiap jurnal harus seimbang (Debit = Kredit).</p>
        </div>
        <div className="page-actions">
          <window.DateRangeFilter from={from} to={to} onChange={({ from, to }) => { setFrom(from); setTo(to); }}/>
          <button className="btn btn-primary" onClick={() => setCreateOpen(true)}><Icon.plus/> Jurnal Baru</button>
        </div>
      </div>

      <div className="grid-4" style={{ marginBottom:18 }}>
        <SmallStatAcc label="Total Jurnal" value={list.length}/>
        <SmallStatAcc label="Draft" value={counts.draft || 0} tone="amber"/>
        <SmallStatAcc label="Diposting" value={counts.posted || 0} tone="green"/>
        <SmallStatAcc label="Dibalik" value={counts.reversed || 0} tone="rose"/>
      </div>

      <div className="card" style={{ overflow:'hidden' }}>
        {loading && <div style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Memuat…</div>}
        {!loading && (
          <table className="table">
            <thead>
              <tr>
                <th>No.</th>
                <th>Tanggal</th>
                <th>Keterangan</th>
                <th>Referensi</th>
                <th style={{ textAlign:'right' }}>Total</th>
                <th>Status</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {list.length === 0 && <tr><td colSpan="7" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Belum ada jurnal.</td></tr>}
              {list.map(e => (
                <tr key={e.id} style={{ cursor:'pointer' }} onClick={() => setOpen(e.id)}>
                  <td><span className="mono" style={{ fontWeight:700 }}>{e.id}</span></td>
                  <td style={{ fontSize:13 }}>{e.entryDate}</td>
                  <td>{e.description}</td>
                  <td><span className="mono" style={{ fontSize:12, color:'var(--ink-500)' }}>{e.reference || '—'}</span></td>
                  <td style={{ textAlign:'right', fontWeight:600 }}>{fmtRp(Number(e.totalDebit))}</td>
                  <td>
                    {e.status === 'draft' && <span className="chip"><span className="chip-dot"/>Draft</span>}
                    {e.status === 'posted' && <span className="chip chip-green"><span className="chip-dot"/>Posted</span>}
                    {e.status === 'reversed' && <span className="chip chip-rose"><span className="chip-dot"/>Reversed</span>}
                  </td>
                  <td style={{ textAlign:'right' }}>
                    <button className="btn btn-secondary btn-sm" onClick={(ev) => { ev.stopPropagation(); setOpen(e.id); }}>Buka</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {createOpen && <CreateJournalModal onClose={() => setCreateOpen(false)} onCreated={load}/>}
      {openId && <JournalDetailModal id={openId} onClose={() => setOpen(null)} onChange={load}/>}
    </div>
  );
}

function CreateJournalModal({ onClose, onCreated }) {
  const [accounts, setAccounts] = useStateAcc([]);
  const [entryDate, setEntryDate] = useStateAcc(new Date().toISOString().slice(0,10));
  const [description, setDescription] = useStateAcc('');
  const [reference, setReference] = useStateAcc('');
  const [lines, setLines] = useStateAcc([
    { accountId: '', debit: '', credit: '', memo: '' },
    { accountId: '', debit: '', credit: '', memo: '' },
  ]);
  const [busy, setBusy] = useStateAcc(false);
  const [error, setError] = useStateAcc('');
  const [postNow, setPostNow] = useStateAcc(true);

  useEffectAcc(() => {
    window.Api.get('/api/accounts').then(r => setAccounts((r.data || []).filter(a => !a.isHeader)));
  }, []);

  const updateLine = (idx, patch) => {
    setLines(lines.map((l, i) => i === idx ? { ...l, ...patch } : l));
  };
  const addLine = () => setLines([...lines, { accountId: '', debit: '', credit: '', memo: '' }]);
  const removeLine = (idx) => setLines(lines.filter((_, i) => i !== idx));

  const totals = useMemoAcc(() => ({
    debit: lines.reduce((s, l) => s + (Number(l.debit) || 0), 0),
    credit: lines.reduce((s, l) => s + (Number(l.credit) || 0), 0),
  }), [lines]);
  const balanced = Math.abs(totals.debit - totals.credit) < 0.001 && totals.debit > 0;

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    if (!balanced) { setError(`Tidak seimbang. Debit Rp${totals.debit} ≠ Kredit Rp${totals.credit}`); return; }
    setBusy(true);
    try {
      await window.Api.post('/api/journals', {
        entryDate, description, reference: reference || undefined,
        status: postNow ? 'posted' : 'draft',
        lines: lines.filter(l => l.accountId).map(l => ({
          accountId: l.accountId,
          debit: Number(l.debit) || 0,
          credit: Number(l.credit) || 0,
          memo: l.memo || undefined,
        })),
      });
      await onCreated();
      onClose();
    } catch (err) {
      setError(err.body?.message || err.message || 'Gagal');
      setBusy(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:880 }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <h2 style={{ margin:0, fontSize:20, fontWeight:800 }}>Jurnal Baru</h2>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <form onSubmit={submit} style={{ padding:'20px 22px', display:'flex', flexDirection:'column', gap:14 }}>
          {error && <div style={{ padding:'10px 14px', background:'#fee2e2', color:'#991b1b', borderRadius:8, fontSize:13 }}>{error}</div>}

          <div style={{ display:'grid', gridTemplateColumns:'180px 1fr 200px', gap:12 }}>
            <FieldAcc label="Tanggal">
              <input className="input" type="date" value={entryDate} onChange={e=>setEntryDate(e.target.value)} required/>
            </FieldAcc>
            <FieldAcc label="Keterangan">
              <input className="input" value={description} onChange={e=>setDescription(e.target.value)} placeholder="Mis. Pencairan saldo Shopee minggu ini" required/>
            </FieldAcc>
            <FieldAcc label="Referensi (opsional)">
              <input className="input" value={reference} onChange={e=>setReference(e.target.value)} placeholder="SMP-2845"/>
            </FieldAcc>
          </div>

          <div>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:8 }}>
              <strong style={{ fontSize:13 }}>Baris Jurnal</strong>
              <button type="button" className="btn btn-secondary btn-sm" onClick={addLine}><Icon.plus/> Tambah Baris</button>
            </div>
            <div style={{ display:'flex', flexDirection:'column', gap:6 }}>
              {lines.map((l, idx) => (
                <div key={idx} style={{ display:'grid', gridTemplateColumns:'2.2fr 130px 130px 1.4fr 32px', gap:6, alignItems:'center' }}>
                  <select className="input" value={l.accountId} onChange={e=>updateLine(idx, { accountId: e.target.value })}>
                    <option value="">— Pilih akun —</option>
                    {accounts.map(a => <option key={a.id} value={a.id}>{a.code} {a.name}</option>)}
                  </select>
                  <input className="input" type="number" min="0" step="any" placeholder="Debit"
                    value={l.debit}
                    onChange={e => {
                      const v = e.target.value;
                      updateLine(idx, { debit: v, credit: v ? '' : l.credit });
                    }}/>
                  <input className="input" type="number" min="0" step="any" placeholder="Kredit"
                    value={l.credit}
                    onChange={e => {
                      const v = e.target.value;
                      updateLine(idx, { credit: v, debit: v ? '' : l.debit });
                    }}/>
                  <input className="input" placeholder="Memo" value={l.memo} onChange={e=>updateLine(idx, { memo: e.target.value })}/>
                  <button type="button" className="tb-icon-btn" onClick={() => removeLine(idx)} disabled={lines.length <= 2}><Icon.x/></button>
                </div>
              ))}
            </div>
            <div style={{ marginTop:10, padding:'10px 14px', borderRadius:8,
              background: balanced ? 'var(--green-bg, #ecfdf3)' : 'var(--amber-bg, #fef9c3)',
              color: balanced ? 'var(--green, #1c8e5a)' : 'var(--amber, #c47a06)',
              display:'flex', alignItems:'center', justifyContent:'space-between', fontSize:13, fontWeight:600 }}>
              <span>{balanced ? '✓ Seimbang' : '⚠ Belum seimbang'}</span>
              <span>Debit {fmtRp(totals.debit)} · Kredit {fmtRp(totals.credit)}</span>
            </div>
          </div>

          <label style={{ display:'flex', alignItems:'center', gap:8, fontSize:13 }}>
            <input type="checkbox" checked={postNow} onChange={e=>setPostNow(e.target.checked)}/>
            Langsung posting (kunci jurnal — tidak bisa diedit)
          </label>

          <div className="modal-foot" style={{ margin:'4px -22px -20px' }}>
            <button type="button" className="btn btn-secondary" onClick={onClose} disabled={busy}>Batal</button>
            <button type="submit" className="btn btn-primary" disabled={busy || !balanced}>
              {busy ? 'Menyimpan…' : (postNow ? 'Simpan & Posting' : 'Simpan Draft')}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

function JournalDetailModal({ id, onClose, onChange }) {
  const [data, setData] = useStateAcc(null);
  const [busy, setBusy] = useStateAcc(false);

  const load = async () => {
    const r = await window.Api.get(`/api/journals/${id}`);
    setData(r.data);
  };
  useEffectAcc(() => { load(); /* eslint-disable-next-line */ }, [id]);

  const post = async () => {
    if (!confirm('Posting jurnal ini? Setelah posting tidak bisa diedit.')) return;
    setBusy(true);
    try { await window.Api.post(`/api/journals/${id}/post`, {}); await load(); await onChange?.(); }
    catch (e) { alert(e.message); }
    finally { setBusy(false); }
  };
  const reverse = async () => {
    if (!confirm('Buat jurnal pembalik? Akan posting otomatis.')) return;
    setBusy(true);
    try { await window.Api.post(`/api/journals/${id}/reverse`, {}); await load(); await onChange?.(); }
    catch (e) { alert(e.message); }
    finally { setBusy(false); }
  };

  if (!data) {
    return (
      <div className="modal-backdrop" onClick={onClose}>
        <div className="modal" style={{ maxWidth:680, padding:40, textAlign:'center' }} onClick={e=>e.stopPropagation()}>Memuat…</div>
      </div>
    );
  }

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:760 }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'.06em', color:'var(--ink-500)' }}>
              Jurnal {data.id}
            </div>
            <h2 style={{ margin:'4px 0 0', fontSize:20, fontWeight:800 }}>{data.description}</h2>
          </div>
          <div style={{ display:'flex', gap:10, alignItems:'center' }}>
            {data.status === 'draft' && <span className="chip"><span className="chip-dot"/>Draft</span>}
            {data.status === 'posted' && <span className="chip chip-green"><span className="chip-dot"/>Posted</span>}
            {data.status === 'reversed' && <span className="chip chip-rose"><span className="chip-dot"/>Reversed</span>}
            <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
          </div>
        </div>
        <div style={{ padding:'14px 22px', display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:14, borderBottom:'1px solid var(--border)' }}>
          <DetailKpiAcc label="Tanggal" value={data.entryDate}/>
          <DetailKpiAcc label="Referensi" value={data.reference || '—'} mono/>
          <DetailKpiAcc label="Total" value={fmtRp(Number(data.totalDebit))}/>
        </div>
        <table className="table">
          <thead>
            <tr>
              <th>Akun</th>
              <th style={{ textAlign:'right' }}>Debit</th>
              <th style={{ textAlign:'right' }}>Kredit</th>
              <th>Memo</th>
            </tr>
          </thead>
          <tbody>
            {data.lines.map(l => (
              <tr key={l.id}>
                <td><span className="mono" style={{ marginRight:6, opacity:.6 }}>{l.accountCode}</span>{l.accountName}</td>
                <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"', fontWeight:600 }}>{Number(l.debit) ? fmtRp(Number(l.debit)) : '—'}</td>
                <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"', fontWeight:600 }}>{Number(l.credit) ? fmtRp(Number(l.credit)) : '—'}</td>
                <td style={{ fontSize:12, color:'var(--ink-500)' }}>{l.memo || ''}</td>
              </tr>
            ))}
          </tbody>
        </table>
        <div className="modal-foot">
          <div style={{ flex:1, fontSize:12, color:'var(--ink-500)' }}>
            {data.status === 'reversed' && data.reversedById && <>Dibalik dengan <strong>{data.reversedById}</strong></>}
          </div>
          <div style={{ display:'flex', gap:8 }}>
            {data.status === 'draft' && <button className="btn btn-primary" onClick={post} disabled={busy}>Posting</button>}
            {data.status === 'posted' && <button className="btn btn-secondary" onClick={reverse} disabled={busy}>Buat Pembalik</button>}
            <button className="btn btn-secondary" onClick={onClose}>Tutup</button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* =========================================================
 * KAS & BANK
 * ========================================================= */
function CashBankPage() {
  const [data, setData] = useStateAcc(null);
  const [transferOpen, setTransferOpen] = useStateAcc(false);
  const [openLedger, setOpenLedger] = useStateAcc(null);

  const load = async () => {
    const r = await window.Api.get('/api/cash-bank');
    setData(r.data);
  };
  useEffectAcc(() => { load(); }, []);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Kas & Bank</h1>
          <p className="page-sub">Saldo seluruh akun kas & bank, dengan riwayat transaksi per akun</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-primary" onClick={() => setTransferOpen(true)}><Icon.flow/> Transfer Antar Kas</button>
        </div>
      </div>

      {data && (
        <>
          <div className="card" style={{ marginBottom:18, padding:'24px 28px', background:'linear-gradient(135deg, var(--brand-50), white)' }}>
            <div style={{ fontSize:13, color:'var(--ink-600)', fontWeight:600, textTransform:'uppercase', letterSpacing:'.04em' }}>
              Total Saldo Kas & Bank
            </div>
            <div style={{ fontSize:40, fontWeight:800, marginTop:6, fontFeatureSettings:'"tnum"' }}>{fmtRp(data.totalBalance)}</div>
            <div style={{ fontSize:13, color:'var(--ink-500)', marginTop:6 }}>
              Kas: <strong>{fmtRp(data.totalCash)}</strong> · Bank: <strong>{fmtRp(data.totalBank)}</strong>
            </div>
          </div>

          <div className="grid-3" style={{ gridTemplateColumns:'repeat(auto-fill, minmax(280px, 1fr))', gap:14 }}>
            {data.accounts.map(a => (
              <div key={a.id} className="card" style={{ padding:'18px 20px', cursor:'pointer' }} onClick={() => setOpenLedger(a)}>
                <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:8 }}>
                  <div style={{ width:34, height:34, borderRadius:8, background: a.subtype==='bank' ? 'var(--blue-bg)' : 'var(--brand-50)', color: a.subtype==='bank' ? 'var(--blue)' : 'var(--brand-500)', display:'grid', placeItems:'center' }}>
                    {a.subtype === 'bank' ? <Icon.flow/> : <Icon.cash/>}
                  </div>
                  <div style={{ flex:1 }}>
                    <div style={{ fontSize:11, color:'var(--ink-500)', fontWeight:600 }}><span className="mono">{a.code}</span> · {a.subtype === 'bank' ? 'Bank' : 'Kas'}</div>
                  </div>
                </div>
                <div style={{ fontSize:14, fontWeight:600, marginBottom:4 }}>{a.name}</div>
                <div style={{ fontSize:24, fontWeight:800, color: a.balance < 0 ? 'var(--rose)' : 'var(--ink-900)', fontFeatureSettings:'"tnum"' }}>
                  {fmtRp(a.balance)}
                </div>
              </div>
            ))}
            {data.accounts.length === 0 && (
              <div style={{ padding:24, textAlign:'center', color:'var(--ink-500)', gridColumn:'1 / -1' }}>
                Belum ada akun kas/bank. Tambahkan via halaman <strong>Akun Perkiraan</strong>.
              </div>
            )}
          </div>
        </>
      )}

      {transferOpen && data && (
        <TransferModal
          accounts={data.accounts}
          onClose={() => setTransferOpen(false)}
          onDone={load}
        />
      )}
      {openLedger && <LedgerModal account={openLedger} onClose={() => setOpenLedger(null)}/>}
    </div>
  );
}

function TransferModal({ accounts, onClose, onDone }) {
  const [from, setFrom] = useStateAcc('');
  const [toAcc, setToAcc] = useStateAcc('');
  const [amount, setAmount] = useStateAcc('');
  const [date, setDate] = useStateAcc(new Date().toISOString().slice(0,10));
  const [description, setDescription] = useStateAcc('Transfer kas/bank');
  const [busy, setBusy] = useStateAcc(false);
  const [error, setError] = useStateAcc('');

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    setBusy(true);
    try {
      await window.Api.post('/api/cash-bank/transfer', {
        fromAccountId: from,
        toAccountId: toAcc,
        amount: Number(amount),
        date,
        description,
      });
      await onDone();
      onClose();
    } catch (err) {
      setError(err.message);
      setBusy(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:520 }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <h2 style={{ margin:0, fontSize:20, fontWeight:800 }}>Transfer Antar Kas/Bank</h2>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <form onSubmit={submit} style={{ padding:'20px 22px', display:'flex', flexDirection:'column', gap:14 }}>
          {error && <div style={{ padding:'10px 14px', background:'#fee2e2', color:'#991b1b', borderRadius:8, fontSize:13 }}>{error}</div>}
          <FieldAcc label="Dari">
            <select className="input" value={from} onChange={e=>setFrom(e.target.value)} required>
              <option value="">— Pilih —</option>
              {accounts.map(a => <option key={a.id} value={a.id}>{a.code} {a.name} (Rp{a.balance.toLocaleString('id-ID')})</option>)}
            </select>
          </FieldAcc>
          <FieldAcc label="Ke">
            <select className="input" value={toAcc} onChange={e=>setToAcc(e.target.value)} required>
              <option value="">— Pilih —</option>
              {accounts.filter(a=>a.id!==from).map(a => <option key={a.id} value={a.id}>{a.code} {a.name}</option>)}
            </select>
          </FieldAcc>
          <FieldAcc label="Jumlah">
            <input className="input" type="number" min="1" step="any" value={amount} onChange={e=>setAmount(e.target.value)} required/>
          </FieldAcc>
          <FieldAcc label="Tanggal">
            <input className="input" type="date" value={date} onChange={e=>setDate(e.target.value)} required/>
          </FieldAcc>
          <FieldAcc label="Keterangan">
            <input className="input" value={description} onChange={e=>setDescription(e.target.value)}/>
          </FieldAcc>
          <div className="modal-foot" style={{ margin:'4px -22px -20px' }}>
            <button type="button" className="btn btn-secondary" onClick={onClose} disabled={busy}>Batal</button>
            <button type="submit" className="btn btn-primary" disabled={busy}>{busy ? 'Memproses…' : 'Transfer'}</button>
          </div>
        </form>
      </div>
    </div>
  );
}

/* =========================================================
 * REKONSILIASI BANK
 * ========================================================= */
function ReconciliationPage() {
  const [list, setList] = useStateAcc([]);
  const [accounts, setAccounts] = useStateAcc([]);
  const [createOpen, setCreateOpen] = useStateAcc(false);
  const [openId, setOpen] = useStateAcc(null);

  const load = async () => {
    const [r1, r2] = await Promise.all([
      window.Api.get('/api/reconciliations'),
      window.Api.get('/api/cash-bank'),
    ]);
    setList(r1.data || []);
    setAccounts(r2.data?.accounts || []);
  };
  useEffectAcc(() => { load(); }, []);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Rekonsiliasi Bank</h1>
          <p className="page-sub">Cocokkan transaksi pembukuan dengan rekening koran bank</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-primary" onClick={() => setCreateOpen(true)} disabled={accounts.length === 0}><Icon.plus/> Sesi Rekonsiliasi Baru</button>
        </div>
      </div>

      <div className="card" style={{ overflow:'hidden' }}>
        <table className="table">
          <thead>
            <tr>
              <th>ID</th>
              <th>Akun</th>
              <th>Periode</th>
              <th style={{ textAlign:'right' }}>Saldo Rekening</th>
              <th>Status</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {list.length === 0 && <tr><td colSpan="6" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Belum ada sesi rekonsiliasi. Klik <strong>Sesi Rekonsiliasi Baru</strong>.</td></tr>}
            {list.map(r => (
              <tr key={r.id} style={{ cursor:'pointer' }} onClick={() => setOpen(r.id)}>
                <td><span className="mono" style={{ fontWeight:700 }}>{r.id}</span></td>
                <td><span className="mono" style={{ marginRight:6, opacity:.6 }}>{r.accountCode}</span>{r.accountName}</td>
                <td style={{ fontSize:13 }}>{r.periodStart} → {r.periodEnd}</td>
                <td style={{ textAlign:'right', fontWeight:600 }}>{fmtRp(Number(r.statementBalance))}</td>
                <td>
                  {r.status === 'in_progress' && <span className="chip chip-amber"><span className="chip-dot"/>Berlangsung</span>}
                  {r.status === 'complete' && <span className="chip chip-green"><span className="chip-dot"/>Selesai</span>}
                </td>
                <td style={{ textAlign:'right' }}>
                  <button className="btn btn-secondary btn-sm" onClick={(e)=>{ e.stopPropagation(); setOpen(r.id); }}>Buka</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {createOpen && <CreateReconModal accounts={accounts} onClose={() => setCreateOpen(false)} onCreated={(id) => { load(); setOpen(id); }}/>}
      {openId && <ReconDetailModal id={openId} onClose={() => setOpen(null)} onChange={load}/>}
    </div>
  );
}

function CreateReconModal({ accounts, onClose, onCreated }) {
  const [accountId, setAccountId] = useStateAcc('');
  const [periodStart, setPeriodStart] = useStateAcc('');
  const [periodEnd, setPeriodEnd] = useStateAcc(new Date().toISOString().slice(0,10));
  const [statementBalance, setStatementBalance] = useStateAcc('');
  const [busy, setBusy] = useStateAcc(false);
  const [error, setError] = useStateAcc('');

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    setBusy(true);
    try {
      const r = await window.Api.post('/api/reconciliations', {
        accountId, periodStart, periodEnd, statementBalance: Number(statementBalance),
      });
      onCreated(r.data.id);
      onClose();
    } catch (err) {
      setError(err.message); setBusy(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:520 }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <h2 style={{ margin:0, fontSize:20, fontWeight:800 }}>Sesi Rekonsiliasi Baru</h2>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <form onSubmit={submit} style={{ padding:'20px 22px', display:'flex', flexDirection:'column', gap:14 }}>
          {error && <div style={{ padding:'10px 14px', background:'#fee2e2', color:'#991b1b', borderRadius:8, fontSize:13 }}>{error}</div>}
          <FieldAcc label="Akun bank/kas">
            <select className="input" value={accountId} onChange={e=>setAccountId(e.target.value)} required>
              <option value="">— Pilih —</option>
              {accounts.map(a => <option key={a.id} value={a.id}>{a.code} {a.name}</option>)}
            </select>
          </FieldAcc>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12 }}>
            <FieldAcc label="Periode mulai">
              <input className="input" type="date" value={periodStart} onChange={e=>setPeriodStart(e.target.value)} required/>
            </FieldAcc>
            <FieldAcc label="Periode akhir">
              <input className="input" type="date" value={periodEnd} onChange={e=>setPeriodEnd(e.target.value)} required/>
            </FieldAcc>
          </div>
          <FieldAcc label="Saldo akhir per rekening koran">
            <input className="input" type="number" step="any" value={statementBalance} onChange={e=>setStatementBalance(e.target.value)} required/>
          </FieldAcc>
          <div className="modal-foot" style={{ margin:'4px -22px -20px' }}>
            <button type="button" className="btn btn-secondary" onClick={onClose} disabled={busy}>Batal</button>
            <button type="submit" className="btn btn-primary" disabled={busy}>{busy ? 'Memproses…' : 'Mulai Rekonsiliasi'}</button>
          </div>
        </form>
      </div>
    </div>
  );
}

function ReconDetailModal({ id, onClose, onChange }) {
  const [data, setData] = useStateAcc(null);
  const [busy, setBusy] = useStateAcc(false);
  const [importResult, setImportResult] = useStateAcc(null);

  const load = async () => {
    const r = await window.Api.get(`/api/reconciliations/${id}`);
    setData(r.data);
  };
  useEffectAcc(() => { load(); /* eslint-disable-next-line */ }, [id]);

  const onCsvFile = async (file) => {
    if (!file) return;
    setBusy(true);
    try {
      const csv = await file.text();
      const r = await window.Api.post(`/api/reconciliations/${id}/import-csv`, { csv });
      setImportResult(r.data);
      await load();
      await onChange?.();
    } catch (e) {
      alert('Gagal import: ' + (e.body?.message || e.message));
    } finally { setBusy(false); }
  };

  const toggleMatch = async (line) => {
    setBusy(true);
    try {
      await window.Api.patch(`/api/reconciliations/${id}/match`, {
        journalLineId: line.lineId,
        matched: !line.matched,
      });
      await load();
    } finally { setBusy(false); }
  };

  const complete = async () => {
    if (!confirm('Selesaikan sesi rekonsiliasi?')) return;
    setBusy(true);
    try {
      await window.Api.post(`/api/reconciliations/${id}/complete`, {});
      await load();
      await onChange?.();
    } finally { setBusy(false); }
  };

  if (!data) return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:680, padding:40, textAlign:'center' }} onClick={e=>e.stopPropagation()}>Memuat…</div>
    </div>
  );

  const reconciled = Math.abs(data.difference) < 0.01;

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:1000, maxHeight:'90vh', display:'flex', flexDirection:'column' }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <div>
            <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'.06em', color:'var(--ink-500)' }}>Rekonsiliasi {data.id}</div>
            <h2 style={{ margin:'4px 0 0', fontSize:20, fontWeight:800 }}>
              <span className="mono" style={{ marginRight:6, opacity:.6 }}>{data.account.code}</span>{data.account.name}
            </h2>
          </div>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <div style={{ padding:'14px 22px', display:'grid', gridTemplateColumns:'repeat(4, 1fr)', gap:12, borderBottom:'1px solid var(--border)' }}>
          <DetailKpiAcc label="Saldo Buku" value={fmtRp(data.bookBalance)}/>
          <DetailKpiAcc label="Saldo Bank" value={fmtRp(data.statementBalance)}/>
          <DetailKpiAcc label="Sudah Cocok" value={fmtRp(data.matchedSum)} tone="green"/>
          <DetailKpiAcc label="Selisih" value={fmtRp(data.difference)} tone={reconciled ? 'green' : 'amber'}/>
        </div>

        {data.status !== 'complete' && (
          <div style={{ padding:'10px 22px', borderBottom:'1px solid var(--border)', display:'flex', alignItems:'center', gap:14, background:'var(--surface-2)' }}>
            <div style={{ fontSize:13, fontWeight:600, color:'var(--ink-700)' }}>📥 Import rekening koran:</div>
            <label className="btn btn-secondary btn-sm" style={{ cursor:'pointer' }}>
              Pilih CSV…
              <input type="file" accept=".csv,text/csv" style={{ display:'none' }} onChange={(e) => onCsvFile(e.target.files?.[0])}/>
            </label>
            <span style={{ fontSize:11.5, color:'var(--ink-500)' }}>
              Format: <code>date, description, debit, credit</code> atau <code>date, description, amount</code>
            </span>
            {importResult && (
              <span style={{ marginLeft:'auto', fontSize:13, color:'var(--green)', fontWeight:600 }}>
                ✓ {importResult.matched} dari {importResult.totalRows} baris auto-cocok
              </span>
            )}
          </div>
        )}
        <div style={{ overflow:'auto', flex:1 }}>
          <table className="table">
            <thead style={{ position:'sticky', top:0, background:'var(--surface)' }}>
              <tr>
                <th style={{ width:36 }}></th>
                <th>Tanggal</th>
                <th>No. Jurnal</th>
                <th>Keterangan</th>
                <th style={{ textAlign:'right' }}>Debit</th>
                <th style={{ textAlign:'right' }}>Kredit</th>
              </tr>
            </thead>
            <tbody>
              {data.lines.length === 0 && <tr><td colSpan="6" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Belum ada transaksi pada akun ini di periode terpilih.</td></tr>}
              {data.lines.map(l => (
                <tr key={l.lineId} style={{ background: l.matched ? 'var(--green-bg, #ecfdf3)' : 'transparent' }}>
                  <td>
                    <input
                      type="checkbox"
                      checked={l.matched}
                      disabled={data.status === 'complete' || busy}
                      onChange={() => toggleMatch(l)}
                    />
                  </td>
                  <td>{l.entryDate}</td>
                  <td><span className="mono" style={{ fontSize:12 }}>{l.entryId}</span></td>
                  <td>{l.description}</td>
                  <td style={{ textAlign:'right' }}>{Number(l.debit) ? fmtRp(Number(l.debit)) : '—'}</td>
                  <td style={{ textAlign:'right' }}>{Number(l.credit) ? fmtRp(Number(l.credit)) : '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div className="modal-foot">
          <div style={{ flex:1, fontSize:12.5, color: reconciled ? 'var(--green)' : 'var(--ink-500)' }}>
            {reconciled ? '✓ Saldo cocok — siap diselesaikan' : `⚠ Selisih ${fmtRp(data.difference)}`}
          </div>
          <div style={{ display:'flex', gap:8 }}>
            {data.status === 'in_progress' && (
              <button className="btn btn-primary" onClick={complete} disabled={busy || !reconciled}>Selesaikan</button>
            )}
            <button className="btn btn-secondary" onClick={onClose}>Tutup</button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* =========================================================
 * NERACA SALDO (Trial Balance)
 * ========================================================= */
function TrialBalancePage() {
  const [data, setData] = useStateAcc(null);
  const [asOf, setAsOf] = useStateAcc(new Date().toISOString().slice(0,10));

  useEffectAcc(() => {
    window.Api.get(`/api/finance/trial-balance?asOf=${asOf}`).then(r => setData(r.data));
  }, [asOf]);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Neraca Saldo</h1>
          <p className="page-sub">Trial balance · seluruh akun yang punya transaksi diposting per tanggal {asOf}</p>
        </div>
        <div className="page-actions">
          <input className="input" type="date" value={asOf} onChange={e=>setAsOf(e.target.value)} style={{ padding:'8px 12px' }}/>
          <button className="btn btn-secondary"><Icon.download/> Ekspor</button>
        </div>
      </div>

      {data && (
        <div className="card" style={{ overflow:'hidden' }}>
          <table className="table table-finance">
            <thead>
              <tr>
                <th style={{ width:90 }}>Kode</th>
                <th>Akun</th>
                <th style={{ textAlign:'right' }}>Debit</th>
                <th style={{ textAlign:'right' }}>Kredit</th>
              </tr>
            </thead>
            <tbody>
              {data.lines.filter(l => l.debit || l.credit).map(l => (
                <tr key={l.accountId}>
                  <td><span className="mono">{l.code}</span></td>
                  <td>{l.name}</td>
                  <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"' }}>{l.debit ? fmtRp(l.debit) : '—'}</td>
                  <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"' }}>{l.credit ? fmtRp(l.credit) : '—'}</td>
                </tr>
              ))}
              <tr style={{ background: data.balanced ? 'var(--green-bg)' : 'var(--amber-bg)', borderTop:'2px solid var(--brand-300)' }}>
                <td colSpan="2" style={{ fontWeight:800, padding:'12px 16px' }}>
                  TOTAL {data.balanced ? '✓ Seimbang' : '⚠ Tidak Seimbang'}
                </td>
                <td style={{ textAlign:'right', fontWeight:800, fontSize:15 }}>{fmtRp(data.totalDebit)}</td>
                <td style={{ textAlign:'right', fontWeight:800, fontSize:15 }}>{fmtRp(data.totalCredit)}</td>
              </tr>
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

/* =========================================================
 * Shared
 * ========================================================= */
function FieldAcc({ label, children }) {
  return (
    <label style={{ display:'flex', flexDirection:'column', gap:6 }}>
      <span style={{ fontSize:12, fontWeight:600, color:'var(--ink-700)' }}>{label}</span>
      {children}
    </label>
  );
}
function SmallStatAcc({ label, value, tone, active, onClick }) {
  const colors = { asset:'var(--brand-500)', liability:'var(--amber)', equity:'var(--blue)', revenue:'var(--green)', expense:'var(--rose)', amber:'var(--amber)', green:'var(--green)', rose:'var(--rose)' };
  return (
    <div className="metric" onClick={onClick} style={{
      cursor: onClick ? 'pointer' : 'default',
      borderColor: active ? 'var(--brand-500)' : undefined,
      background: active ? 'var(--brand-50)' : undefined,
    }}>
      <div className="metric-label">{label}</div>
      <div className="metric-value" style={{ color: tone ? colors[tone] : undefined }}>{value}</div>
    </div>
  );
}
function DetailKpiAcc({ label, value, mono, tone }) {
  const colors = { green:'var(--green)', amber:'var(--amber)', rose:'var(--rose)', brand:'var(--brand-500)' };
  return (
    <div>
      <div style={{ fontSize:11, fontWeight:600, color:'var(--ink-500)', textTransform:'uppercase', letterSpacing:'.05em' }}>{label}</div>
      <div className={mono ? 'mono' : ''} style={{ fontSize:18, fontWeight:700, marginTop:4, color: tone ? colors[tone] : undefined }}>{value}</div>
    </div>
  );
}

/* =========================================================
 * BUKU BESAR LENGKAP — semua akun + lines
 * ========================================================= */
function GeneralLedgerPage() {
  const [data, setData] = useStateAcc(null);
  const [from, setFrom] = useStateAcc('');
  const [to, setTo] = useStateAcc('');
  const [expanded, setExpanded] = useStateAcc(new Set());

  useEffectAcc(() => {
    const q = new URLSearchParams();
    if (from) q.set('from', from);
    if (to) q.set('to', to);
    window.Api.get(`/api/finance/general-ledger?${q.toString()}`).then(r => setData(r.data));
  }, [from, to]);

  const toggle = (id) => {
    const s = new Set(expanded);
    s.has(id) ? s.delete(id) : s.add(id);
    setExpanded(s);
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Buku Besar</h1>
          <p className="page-sub">Riwayat transaksi seluruh akun yang punya postingan dalam rentang tanggal terpilih</p>
        </div>
        <div className="page-actions">
          <window.DateRangeFilter from={from} to={to} onChange={({ from, to }) => { setFrom(from); setTo(to); }}/>
          <button className="btn btn-secondary"><Icon.download/> Ekspor</button>
        </div>
      </div>

      {!data && <div className="card" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Memuat…</div>}
      {data && data.length === 0 && (
        <div className="card" style={{ padding:40, textAlign:'center', color:'var(--ink-500)' }}>
          Tidak ada akun dengan transaksi pada rentang ini.
        </div>
      )}
      {data && data.map(acc => {
        const isOpen = expanded.has(acc.accountId);
        const meta = TYPE_LABEL[acc.type];
        return (
          <div key={acc.accountId} className="card" style={{ marginBottom:10, overflow:'hidden' }}>
            <div
              onClick={() => toggle(acc.accountId)}
              style={{
                display:'flex', alignItems:'center', gap:14,
                padding:'14px 18px',
                cursor:'pointer',
                background: isOpen ? 'var(--brand-50)' : 'white',
                borderBottom: isOpen ? '1px solid var(--border)' : 'none',
              }}
            >
              <span style={{ fontSize:11, color:'var(--ink-500)', width:14 }}>{isOpen ? '▼' : '▶'}</span>
              <span className="mono" style={{ fontWeight:700, width:60 }}>{acc.code}</span>
              <span style={{ fontWeight:600, flex:1 }}>{acc.name}</span>
              <span className="chip" style={{ background:`${meta.color}1a`, color:meta.color, fontSize:11 }}>{meta.label}</span>
              <span style={{ fontSize:12, color:'var(--ink-500)' }}>{acc.lineCount} transaksi</span>
              <span style={{ fontWeight:700, fontFeatureSettings:'"tnum"', minWidth:140, textAlign:'right',
                color: acc.closingBalance < 0 ? 'var(--rose)' : 'var(--ink-900)' }}>{fmtRp(acc.closingBalance)}</span>
            </div>
            {isOpen && (
              <table className="table">
                <thead>
                  <tr>
                    <th>Tanggal</th>
                    <th>Jurnal</th>
                    <th>Keterangan</th>
                    <th style={{ textAlign:'right' }}>Debit</th>
                    <th style={{ textAlign:'right' }}>Kredit</th>
                    <th style={{ textAlign:'right' }}>Saldo</th>
                  </tr>
                </thead>
                <tbody>
                  {acc.lines.map(l => (
                    <tr key={l.lineId}>
                      <td>{l.entryDate}</td>
                      <td><span className="mono" style={{ fontSize:12 }}>{l.entryId}</span></td>
                      <td>{l.description}{l.memo && <span style={{ fontSize:11, color:'var(--ink-500)', marginLeft:6 }}>· {l.memo}</span>}</td>
                      <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"' }}>{Number(l.debit) ? fmtRp(Number(l.debit)) : '—'}</td>
                      <td style={{ textAlign:'right', fontFeatureSettings:'"tnum"' }}>{Number(l.credit) ? fmtRp(Number(l.credit)) : '—'}</td>
                      <td style={{ textAlign:'right', fontWeight:600, fontFeatureSettings:'"tnum"' }}>{fmtRp(l.runningBalance)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </div>
        );
      })}
    </div>
  );
}

/* =========================================================
 * JURNAL BERULANG (Recurring Journal)
 * ========================================================= */
function RecurringPage() {
  const [list, setList] = useStateAcc([]);
  const [createOpen, setCreateOpen] = useStateAcc(false);
  const [busy, setBusy] = useStateAcc(null);

  const load = async () => {
    const r = await window.Api.get('/api/recurring');
    setList(r.data || []);
  };
  useEffectAcc(() => { load(); }, []);

  const runNow = async (id) => {
    if (!confirm('Jalankan template ini sekarang? Akan bikin jurnal posted baru.')) return;
    setBusy(id);
    try { await window.Api.post(`/api/recurring/${id}/run`, {}); await load(); }
    catch (e) { alert('Gagal: ' + e.message); }
    finally { setBusy(null); }
  };
  const toggleActive = async (r) => {
    setBusy(r.id);
    try { await window.Api.patch(`/api/recurring/${r.id}`, { isActive: !r.isActive }); await load(); }
    finally { setBusy(null); }
  };
  const remove = async (id) => {
    if (!confirm('Hapus template ini?')) return;
    setBusy(id);
    try { await window.Api.del(`/api/recurring/${id}`); await load(); }
    finally { setBusy(null); }
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Jurnal Berulang</h1>
          <p className="page-sub">Template jurnal yang dijalankan rutin — sewa bulanan, gaji, depresiasi, dll.</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-primary" onClick={() => setCreateOpen(true)}><Icon.plus/> Template Baru</button>
        </div>
      </div>

      <div className="card" style={{ overflow:'hidden' }}>
        <table className="table">
          <thead>
            <tr>
              <th>Nama</th>
              <th>Frekuensi</th>
              <th>Jadwal Berikutnya</th>
              <th>Terakhir Dijalankan</th>
              <th style={{ textAlign:'right' }}>Total</th>
              <th>Aktif</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {list.length === 0 && <tr><td colSpan="7" style={{ padding:24, textAlign:'center', color:'var(--ink-500)' }}>Belum ada template berulang.</td></tr>}
            {list.map(r => (
              <tr key={r.id} style={{ background: !r.isActive ? 'var(--surface-2)' : 'white' }}>
                <td>
                  <div style={{ fontWeight:600 }}>{r.name}</div>
                  <div style={{ fontSize:12, color:'var(--ink-500)' }}>{r.description}</div>
                </td>
                <td><span className="chip">{r.frequency === 'monthly' ? 'Bulanan' : r.frequency === 'weekly' ? 'Mingguan' : 'Tahunan'}</span></td>
                <td style={{ fontSize:13 }}>{r.nextRunOn}</td>
                <td style={{ fontSize:13, color:'var(--ink-500)' }}>{r.lastRunAt ? new Date(r.lastRunAt).toLocaleDateString('id-ID') : 'Belum'}</td>
                <td style={{ textAlign:'right', fontWeight:600 }}>{fmtRp(Number(r.totalAmount))}</td>
                <td>
                  <label style={{ display:'inline-flex', alignItems:'center', gap:6, cursor:'pointer' }}>
                    <input type="checkbox" checked={r.isActive} disabled={busy === r.id} onChange={() => toggleActive(r)}/>
                    <span style={{ fontSize:12 }}>{r.isActive ? 'Aktif' : 'Nonaktif'}</span>
                  </label>
                </td>
                <td style={{ textAlign:'right' }}>
                  <div style={{ display:'inline-flex', gap:6 }}>
                    <button className="btn btn-primary btn-sm" disabled={busy === r.id} onClick={() => runNow(r.id)}>Jalankan</button>
                    <button className="btn btn-secondary btn-sm" disabled={busy === r.id} onClick={() => remove(r.id)}>Hapus</button>
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {createOpen && <CreateRecurringModal onClose={() => setCreateOpen(false)} onCreated={load}/>}
    </div>
  );
}

function CreateRecurringModal({ onClose, onCreated }) {
  const [accounts, setAccounts] = useStateAcc([]);
  const [name, setName] = useStateAcc('');
  const [description, setDescription] = useStateAcc('');
  const [frequency, setFrequency] = useStateAcc('monthly');
  const [nextRunOn, setNextRunOn] = useStateAcc(new Date().toISOString().slice(0,10));
  const [lines, setLines] = useStateAcc([
    { accountId: '', debit: '', credit: '', memo: '' },
    { accountId: '', debit: '', credit: '', memo: '' },
  ]);
  const [busy, setBusy] = useStateAcc(false);
  const [error, setError] = useStateAcc('');

  useEffectAcc(() => {
    window.Api.get('/api/accounts').then(r => setAccounts((r.data || []).filter(a => !a.isHeader)));
  }, []);

  const updateLine = (idx, patch) => setLines(lines.map((l, i) => i === idx ? { ...l, ...patch } : l));
  const addLine = () => setLines([...lines, { accountId:'', debit:'', credit:'', memo:'' }]);
  const removeLine = (idx) => setLines(lines.filter((_, i) => i !== idx));

  const totals = useMemoAcc(() => ({
    debit: lines.reduce((s, l) => s + (Number(l.debit) || 0), 0),
    credit: lines.reduce((s, l) => s + (Number(l.credit) || 0), 0),
  }), [lines]);
  const balanced = Math.abs(totals.debit - totals.credit) < 0.001 && totals.debit > 0;

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    if (!balanced) { setError('Tidak seimbang'); return; }
    setBusy(true);
    try {
      await window.Api.post('/api/recurring', {
        name, description, frequency, nextRunOn,
        lines: lines.filter(l => l.accountId).map(l => ({
          accountId: l.accountId,
          debit: Number(l.debit) || 0,
          credit: Number(l.credit) || 0,
          memo: l.memo || undefined,
        })),
      });
      await onCreated();
      onClose();
    } catch (err) {
      setError(err.message); setBusy(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ maxWidth:760 }} onClick={e=>e.stopPropagation()}>
        <div className="modal-head">
          <h2 style={{ margin:0, fontSize:20, fontWeight:800 }}>Template Jurnal Berulang</h2>
          <button className="tb-icon-btn" onClick={onClose}><Icon.x/></button>
        </div>
        <form onSubmit={submit} style={{ padding:'20px 22px', display:'flex', flexDirection:'column', gap:14 }}>
          {error && <div style={{ padding:'10px 14px', background:'#fee2e2', color:'#991b1b', borderRadius:8, fontSize:13 }}>{error}</div>}
          <div style={{ display:'grid', gridTemplateColumns:'1fr 2fr', gap:12 }}>
            <FieldAcc label="Nama">
              <input className="input" value={name} onChange={e=>setName(e.target.value)} placeholder="Sewa Gudang Bulanan" required/>
            </FieldAcc>
            <FieldAcc label="Keterangan">
              <input className="input" value={description} onChange={e=>setDescription(e.target.value)} placeholder="Sewa rak gudang Surabaya" required/>
            </FieldAcc>
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12 }}>
            <FieldAcc label="Frekuensi">
              <select className="input" value={frequency} onChange={e=>setFrequency(e.target.value)}>
                <option value="weekly">Mingguan</option>
                <option value="monthly">Bulanan</option>
                <option value="yearly">Tahunan</option>
              </select>
            </FieldAcc>
            <FieldAcc label="Tanggal jalankan berikutnya">
              <input className="input" type="date" value={nextRunOn} onChange={e=>setNextRunOn(e.target.value)} required/>
            </FieldAcc>
          </div>

          <div>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:8 }}>
              <strong style={{ fontSize:13 }}>Baris Jurnal</strong>
              <button type="button" className="btn btn-secondary btn-sm" onClick={addLine}><Icon.plus/> Tambah</button>
            </div>
            {lines.map((l, idx) => (
              <div key={idx} style={{ display:'grid', gridTemplateColumns:'2.2fr 130px 130px 1.4fr 32px', gap:6, alignItems:'center', marginBottom:6 }}>
                <select className="input" value={l.accountId} onChange={e=>updateLine(idx, { accountId: e.target.value })}>
                  <option value="">— Akun —</option>
                  {accounts.map(a => <option key={a.id} value={a.id}>{a.code} {a.name}</option>)}
                </select>
                <input className="input" type="number" placeholder="Debit" value={l.debit}
                  onChange={e => { const v = e.target.value; updateLine(idx, { debit: v, credit: v ? '' : l.credit }); }}/>
                <input className="input" type="number" placeholder="Kredit" value={l.credit}
                  onChange={e => { const v = e.target.value; updateLine(idx, { credit: v, debit: v ? '' : l.debit }); }}/>
                <input className="input" placeholder="Memo" value={l.memo} onChange={e=>updateLine(idx, { memo: e.target.value })}/>
                <button type="button" className="tb-icon-btn" onClick={() => removeLine(idx)} disabled={lines.length <= 2}><Icon.x/></button>
              </div>
            ))}
            <div style={{ marginTop:6, padding:'8px 12px', borderRadius:8,
              background: balanced ? 'var(--green-bg)' : 'var(--amber-bg)',
              color: balanced ? 'var(--green)' : 'var(--amber)', fontSize:12, fontWeight:600,
              display:'flex', justifyContent:'space-between' }}>
              <span>{balanced ? '✓ Seimbang' : '⚠ Belum seimbang'}</span>
              <span>D {fmtRp(totals.debit)} · C {fmtRp(totals.credit)}</span>
            </div>
          </div>

          <div className="modal-foot" style={{ margin:'4px -22px -20px' }}>
            <button type="button" className="btn btn-secondary" onClick={onClose} disabled={busy}>Batal</button>
            <button type="submit" className="btn btn-primary" disabled={busy || !balanced}>{busy ? 'Menyimpan…' : 'Simpan Template'}</button>
          </div>
        </form>
      </div>
    </div>
  );
}

/* =========================================================
 * TUTUP BUKU (Closing Entries)
 * ========================================================= */
function ClosingPage() {
  const [asOf, setAsOf] = useStateAcc(() => {
    const d = new Date();
    return new Date(d.getFullYear(), d.getMonth() + 1, 0).toISOString().slice(0, 10);
  });
  const [transferToRE, setTransferToRE] = useStateAcc(false);
  const [busy, setBusy] = useStateAcc(false);
  const [result, setResult] = useStateAcc(null);
  const [error, setError] = useStateAcc('');

  const close = async () => {
    if (!confirm(`Jalankan jurnal penutup per ${asOf}? Operasi ini tidak bisa dibatalkan otomatis (perlu reversal manual).`)) return;
    setError('');
    setBusy(true);
    try {
      const r = await window.Api.post('/api/finance/close-period', { asOf, transferToRetainedEarnings: transferToRE });
      setResult(r.data);
    } catch (e) {
      setError(e.message);
    } finally { setBusy(false); }
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1 className="page-title">Tutup Buku</h1>
          <p className="page-sub">Jurnal penutup — pindahkan saldo Pendapatan & Beban ke Laba Tahun Berjalan, lalu (opsional) ke Laba Ditahan</p>
        </div>
      </div>

      <div className="card" style={{ padding:'24px 28px', maxWidth:680 }}>
        <FieldAcc label="Tanggal penutupan (akhir periode)">
          <input className="input" type="date" value={asOf} onChange={e=>setAsOf(e.target.value)}/>
        </FieldAcc>
        <label style={{ display:'flex', alignItems:'center', gap:8, marginTop:14, fontSize:13 }}>
          <input type="checkbox" checked={transferToRE} onChange={e=>setTransferToRE(e.target.checked)}/>
          Sekaligus pindah Laba Tahun Berjalan ke <strong>Laba Ditahan (3120)</strong> — biasanya dilakukan akhir tahun
        </label>

        <div style={{ marginTop:18, padding:'14px 16px', background:'var(--amber-bg)', color:'var(--amber)', borderRadius:8, fontSize:13 }}>
          ⚠ <strong>Apa yang akan terjadi:</strong>
          <ul style={{ margin:'8px 0 0 20px', padding:0 }}>
            <li>Saldo akhir setiap akun Pendapatan (4xxx) di-zero, dipindah ke 3130 Laba Tahun Berjalan</li>
            <li>Saldo akhir setiap akun Beban (5xxx) di-zero, dipindah ke 3130 Laba Tahun Berjalan</li>
            <li>1 jurnal penutup terbentuk dengan sumber <code>manual</code> + reference <code>CLOSE-{asOf}</code></li>
            {transferToRE && <li>Tambahan jurnal: 3130 di-zero, ditransfer ke 3120 Laba Ditahan</li>}
          </ul>
        </div>

        {error && <div style={{ marginTop:14, padding:'10px 14px', background:'#fee2e2', color:'#991b1b', borderRadius:8, fontSize:13 }}>{error}</div>}

        {result && (
          <div style={{ marginTop:14, padding:'14px 16px', background:'var(--green-bg)', color:'var(--green)', borderRadius:8, fontSize:13 }}>
            ✓ <strong>Selesai.</strong>
            {result.skipped ? (
              <> {result.message}</>
            ) : (
              <>
                <div style={{ marginTop:6 }}>Jurnal penutup: <strong>{result.closing?.id}</strong></div>
                <div>Laba/Rugi bersih periode: <strong>{fmtRp(result.netResult)}</strong></div>
                {result.transfer && <div>Transfer ke Laba Ditahan: <strong>{result.transfer.id}</strong></div>}
              </>
            )}
          </div>
        )}

        <div style={{ marginTop:18, display:'flex', justifyContent:'flex-end' }}>
          <button className="btn btn-primary" onClick={close} disabled={busy}>{busy ? 'Memproses…' : 'Jalankan Tutup Buku'}</button>
        </div>
      </div>
    </div>
  );
}

window.AccountsPage = AccountsPage;
window.JournalsPage = JournalsPage;
window.CashBankPage = CashBankPage;
window.ReconciliationPage = ReconciliationPage;
window.TrialBalancePage = TrialBalancePage;
window.GeneralLedgerPage = GeneralLedgerPage;
window.RecurringPage = RecurringPage;
window.ClosingPage = ClosingPage;
