// flows.jsx — Claims (+ log-a-claim flow) and Invoices vault
const { useState: uS, useEffect: uE } = React;

const catName = (k) => (Store.doc.budget.find((b) => b.key === k) || {}).name || k;
const catColor = (k) => (Store.doc.budget.find((b) => b.key === k) || {}).color || 'var(--ink-2)';
const catSoft = (k) => (Store.doc.budget.find((b) => b.key === k) || {}).soft || 'var(--surface-2)';

// delete with a built-in second click to confirm (disarms after 3s)
function DangerBtn({ onConfirm, label = 'Delete', title }) {
  const [armed, setArmed] = uS(false);
  uE(() => { if (armed) { const t = setTimeout(() => setArmed(false), 3000); return () => clearTimeout(t); } }, [armed]);
  return (
    <button title={title} onClick={(e) => { e.stopPropagation(); if (armed) { onConfirm(); setArmed(false); } else setArmed(true); }} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, padding: '7px 11px', fontSize: 13, fontWeight: 600,
      borderRadius: 10, border: '1px solid ' + (armed ? 'var(--alert)' : 'var(--line-2)'), whiteSpace: 'nowrap',
      background: armed ? 'var(--alert)' : 'transparent', color: armed ? '#fff' : 'var(--ink-3)', transition: 'all .15s', flexShrink: 0,
    }}><Icons.trash size={15} />{armed ? 'Sure? Click again' : label}</button>
  );
}

// shared edit-form styles
const editInput = { width: '100%', padding: '11px 13px', fontSize: 14.5, fontFamily: 'var(--sans)', border: '1px solid var(--line-2)', borderRadius: 11, background: 'var(--surface)', color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' };
const editLabel = { fontSize: 13, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6, display: 'block' };

function EditClaim({ claim, onClose }) {
  const [f, setF] = uS(null);
  uE(() => {
    if (claim) setF({ provider: claim.provider, cat: claim.cat, sub: claim.sub || '', date: claim.date, amount: String(claim.amount), invoice: claim.invoice || '' });
  }, [claim]);
  if (!claim || !f) return null;
  const set = (k, v) => setF((x) => ({ ...x, [k]: v }));
  const canSave = f.provider && f.cat && f.amount;
  return (
    <Modal open={true} onClose={onClose} width={520} title="Edit claim" sub="The budget adjusts automatically when you save.">
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div>
          <label style={editLabel}>Provider</label>
          <input list="haven-prov-list-2" style={editInput} value={f.provider} onChange={(e) => set('provider', e.target.value)} />
          <datalist id="haven-prov-list-2">{Store.doc.providers.map((p) => <option key={p.id} value={p.short || p.name} />)}</datalist>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <div>
            <label style={editLabel}>Budget category</label>
            <select style={editInput} value={f.cat} onChange={(e) => set('cat', e.target.value)}>
              {Store.doc.budget.map((b) => <option key={b.key} value={b.key}>{b.name}</option>)}
            </select>
          </div>
          <div><label style={editLabel}>Support date</label><input type="date" style={editInput} value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <div>
            <label style={editLabel}>Amount (inc. GST)</label>
            <div style={{ position: 'relative' }}>
              <span style={{ position: 'absolute', left: 13, top: 11, color: 'var(--ink-3)', fontSize: 14.5 }}>$</span>
              <input type="number" style={{ ...editInput, paddingLeft: 24 }} value={f.amount} onChange={(e) => set('amount', e.target.value)} />
            </div>
          </div>
          <div><label style={editLabel}>Invoice / receipt no.</label><input style={editInput} value={f.invoice} onChange={(e) => set('invoice', e.target.value)} /></div>
        </div>
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button icon={Icons.check} disabled={!canSave} onClick={() => { Store.updateClaim(claim.id, f); onClose(); }} style={{ opacity: canSave ? 1 : 0.5, pointerEvents: canSave ? 'auto' : 'none' }}>Save changes</Button>
        </div>
      </div>
    </Modal>
  );
}

function EditInvoice({ inv, onClose }) {
  const [f, setF] = uS(null);
  uE(() => { if (inv) setF({ provider: inv.provider, cat: inv.cat, date: inv.date, amount: String(inv.amount) }); }, [inv]);
  if (!inv || !f) return null;
  const set = (k, v) => setF((x) => ({ ...x, [k]: v }));
  const canSave = f.provider && f.amount;
  return (
    <Modal open={true} onClose={onClose} width={480} title="Edit invoice" sub={`Record ${inv.id}`}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div>
          <label style={editLabel}>Provider</label>
          <input list="haven-prov-list-3" style={editInput} value={f.provider} onChange={(e) => set('provider', e.target.value)} />
          <datalist id="haven-prov-list-3">{Store.doc.providers.map((p) => <option key={p.id} value={p.name} />)}</datalist>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <div>
            <label style={editLabel}>Budget category</label>
            <select style={editInput} value={f.cat} onChange={(e) => set('cat', e.target.value)}>
              {Store.doc.budget.map((b) => <option key={b.key} value={b.key}>{b.name}</option>)}
            </select>
          </div>
          <div><label style={editLabel}>Invoice date</label><input type="date" style={editInput} value={f.date} onChange={(e) => set('date', e.target.value)} /></div>
        </div>
        <div>
          <label style={editLabel}>Amount (inc. GST)</label>
          <div style={{ position: 'relative' }}>
            <span style={{ position: 'absolute', left: 13, top: 11, color: 'var(--ink-3)', fontSize: 14.5 }}>$</span>
            <input type="number" style={{ ...editInput, paddingLeft: 24 }} value={f.amount} onChange={(e) => set('amount', e.target.value)} />
          </div>
        </div>
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button icon={Icons.check} disabled={!canSave} onClick={() => { Store.listPatch('invoices', inv.id, { provider: f.provider, cat: f.cat, date: f.date, amount: parseFloat(f.amount) || inv.amount }); onClose(); }} style={{ opacity: canSave ? 1 : 0.5, pointerEvents: canSave ? 'auto' : 'none' }}>Save changes</Button>
        </div>
      </div>
    </Modal>
  );
}

// ══════════════════════════════════════════════════════════════════
// CLAIMS
// ══════════════════════════════════════════════════════════════════
function Claims({ arg, go, clearArg }) {
  const S = useHaven();
  const claims = S.doc.claims;
  const [filter, setFilter] = uS('all');
  const [logging, setLogging] = uS(false);
  const [expanded, setExpanded] = uS(null);
  const [prefill, setPrefill] = uS(null);
  const [editing, setEditing] = uS(null);

  uE(() => {
    if (arg === 'new') { setLogging(true); clearArg && clearArg(); }
    else if (arg && arg.id) { setPrefill(arg); setLogging(true); clearArg && clearArg(); }
  }, [arg]);

  const counts = {
    all: claims.length,
    todo: claims.filter((c) => c.status === 'draft' || c.status === 'rejected').length,
    submitted: claims.filter((c) => c.status === 'submitted').length,
    paid: claims.filter((c) => c.status === 'paid').length,
  };
  const tabs = [
    { key: 'all', label: 'All claims' },
    { key: 'todo', label: 'Needs you', n: counts.todo },
    { key: 'submitted', label: 'Submitted', n: counts.submitted },
    { key: 'paid', label: 'Paid', n: counts.paid },
  ];
  const shown = claims.filter((c) =>
    filter === 'all' ? true : filter === 'todo' ? (c.status === 'draft' || c.status === 'rejected') : c.status === filter);

  const totalSubmitted = claims.filter((c) => c.status === 'submitted').reduce((s, c) => s + c.amount, 0);

  return (
    <div className="fade-in">
      <PageHead
        title="Claims"
        sub={<>A <PlainTip term="Claim" /> asks the NDIS to pay you back for a support you've already bought. Log it, attach the invoice, send.</>}
        right={<Button icon={Icons.plus} onClick={() => setLogging(true)}>Log a claim</Button>}
      />

      {totalSubmitted > 0 && (
        <div style={{ marginBottom: 18 }}>
          <Note tone="amber" icon="clock"><b>{fmtMoney(totalSubmitted, 2)}</b> is on its way back to you — submitted claims usually land in your bank account within 2–3 business days.</Note>
        </div>
      )}

      {/* tabs */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 18, borderBottom: '1px solid var(--line)' }}>
        {tabs.map((t) => (
          <button key={t.key} onClick={() => setFilter(t.key)} style={{
            background: 'none', border: 'none', padding: '10px 4px', marginRight: 14, fontSize: 14.5, fontWeight: 600,
            color: filter === t.key ? 'var(--primary-ink)' : 'var(--ink-2)', borderBottom: filter === t.key ? '2.5px solid var(--primary)' : '2.5px solid transparent',
            marginBottom: -1, display: 'flex', alignItems: 'center', gap: 7,
          }}>
            {t.label}
            {t.n > 0 && <span style={{ background: filter === t.key ? 'var(--primary-soft)' : 'var(--surface-2)', color: filter === t.key ? 'var(--primary-ink)' : 'var(--ink-2)', borderRadius: 99, fontSize: 12, padding: '1px 8px', fontWeight: 700 }}>{t.n}</span>}
          </button>
        ))}
      </div>

      <Card pad={0}>
        {shown.length === 0 && <div style={{ padding: 40, textAlign: 'center', color: 'var(--ink-3)' }}>Nothing here — all caught up.</div>}
        {shown.map((c, i) => {
          const isOpen = expanded === c.id;
          return (
            <div key={c.id} style={{ borderBottom: i < shown.length - 1 ? '1px solid var(--line)' : 'none' }}>
              <div onClick={() => setExpanded(isOpen ? null : c.id)} style={{ display: 'flex', alignItems: 'center', gap: 16, padding: '16px 22px', cursor: 'pointer' }}>
                <span style={{ width: 10, height: 10, borderRadius: 3, background: catColor(c.cat), flexShrink: 0 }} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 15, fontWeight: 600 }}>{c.provider}</div>
                  <div style={{ fontSize: 13, color: 'var(--ink-2)' }}>{c.sub} · {fmtDateShort(c.date)}</div>
                </div>
                <div style={{ fontSize: 16, fontWeight: 700, fontVariantNumeric: 'tabular-nums', minWidth: 90, textAlign: 'right' }}>{fmtMoney(c.amount, 2)}</div>
                <div style={{ minWidth: 130, display: 'flex', justifyContent: 'flex-end' }}><StatusPill status={c.status} /></div>
                <span style={{ color: 'var(--ink-3)', transform: isOpen ? 'rotate(180deg)' : 'none', transition: 'transform .2s' }}><Icons.chevD size={18} /></span>
              </div>
              {isOpen && (
                <div style={{ padding: '0 22px 20px 48px', animation: 'fadeIn .2s ease both' }}>
                  {c.status === 'rejected' && (
                    <div style={{ marginBottom: 14 }}>
                      <Note tone="amber" icon="alert"><b>Why it bounced:</b> {c.reason} <span style={{ display: 'block', marginTop: 6 }}><a style={{ color: 'var(--primary-ink)', fontWeight: 600, cursor: 'pointer' }} onClick={(e) => { e.stopPropagation(); setPrefill({ provider: c.provider, cat: c.cat, sub: c.sub, amount: c.amount }); setLogging(true); }}>Fix & resubmit →</a></span></Note>
                    </div>
                  )}
                  <ClaimTimeline c={c} />
                  <div style={{ display: 'flex', gap: 22, marginTop: 14, fontSize: 13, color: 'var(--ink-2)', flexWrap: 'wrap' }}>
                    <span>Invoice <b style={{ color: 'var(--ink)' }}>{c.invoice}</b></span>
                    <span><PlainTip term={catName(c.cat)} /></span>
                    <span>Support date <b style={{ color: 'var(--ink)' }}>{fmtDate(c.date)}</b></span>
                  </div>
                  <div style={{ display: 'flex', gap: 8, marginTop: 14, alignItems: 'center', flexWrap: 'wrap' }}>
                    {c.status === 'submitted' && <Button size="sm" variant="soft" icon={Icons.checkCircle} onClick={() => S.setClaimStatus(c.id, 'paid')}>NDIS paid this</Button>}
                    {c.status === 'submitted' && <Button size="sm" variant="ghost" icon={Icons.alert} onClick={() => S.setClaimStatus(c.id, 'rejected')}>It bounced</Button>}
                    <Button size="sm" variant="ghost" icon={Icons.pencil} onClick={() => setEditing(c)}>Edit</Button>
                    <span style={{ flex: 1 }}></span>
                    <DangerBtn title="Removes this claim and puts the money back in the budget" onConfirm={() => S.deleteClaim(c.id)} />
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </Card>

      <LogClaim open={logging} prefill={prefill} onClose={() => { setLogging(false); setPrefill(null); }} onDone={(c) => { S.addClaim(c); setFilter('submitted'); }} />
      <EditClaim claim={editing} onClose={() => setEditing(null)} />
    </div>
  );
}

function ClaimTimeline({ c }) {
  const steps = [
    { label: 'Logged', date: c.date, done: true },
    { label: 'Submitted to NDIS', date: c.submitted, done: !!c.submitted && c.status !== 'draft' },
    c.status === 'rejected'
      ? { label: 'Bounced back', date: c.submitted, done: true, bad: true }
      : { label: 'Paid to you', date: c.paid, done: c.status === 'paid' },
  ];
  return (
    <div style={{ display: 'flex', gap: 0 }}>
      {steps.map((s, i) => (
        <div key={i} style={{ flex: 1, position: 'relative' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span style={{ width: 22, height: 22, borderRadius: '50%', display: 'grid', placeItems: 'center', flexShrink: 0,
              background: s.bad ? 'var(--alert-soft)' : s.done ? 'var(--good-soft)' : 'var(--surface-2)',
              color: s.bad ? 'var(--alert)' : s.done ? 'var(--good)' : 'var(--ink-3)' }}>
              {s.bad ? <Icons.x size={13} /> : s.done ? <Icons.check size={13} /> : <Icons.clock size={13} />}
            </span>
            {i < steps.length - 1 && <span style={{ flex: 1, height: 2, background: steps[i + 1].done || steps[i + 1].bad ? 'var(--good)' : 'var(--line-2)' }} />}
          </div>
          <div style={{ marginTop: 7, fontSize: 12.5, fontWeight: 600, color: s.done ? 'var(--ink)' : 'var(--ink-3)' }}>{s.label}</div>
          {s.date && <div style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>{fmtDateShort(s.date)}</div>}
        </div>
      ))}
    </div>
  );
}

// ── Log-a-claim multi-step flow ─────────────────────────────────────
function LogClaim({ open, onClose, onDone, prefill }) {
  const [step, setStep] = uS(0);
  const blank = { provider: '', cat: '', sub: '', date: TODAY.toISOString().slice(0, 10), amount: '', invoice: '' };
  const [form, setForm] = uS(blank);
  const [file, setFile] = uS(null);
  const [uping, setUping] = uS(false);

  uE(() => {
    if (open) {
      setStep(0); setFile(null); setUping(false);
      if (prefill && prefill.provider) {
        setForm({ provider: prefill.provider, cat: prefill.cat || '', sub: prefill.sub || '', date: TODAY.toISOString().slice(0, 10), amount: prefill.amount || '', invoice: '' });
      } else if (prefill && prefill.id) { // an invoice object
        setForm({ provider: prefill.provider, cat: prefill.cat, sub: '', date: prefill.date, amount: prefill.amount, invoice: prefill.id });
      } else setForm(blank);
    }
  }, [open]);

  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const provObj = Store.doc.providers.find((p) => p.name === form.provider || p.short === form.provider);
  const canNext = form.provider && form.cat && form.amount;

  const inputStyle = { width: '100%', padding: '11px 13px', fontSize: 14.5, fontFamily: 'var(--sans)', border: '1px solid var(--line-2)', borderRadius: 11, background: 'var(--surface)', color: 'var(--ink)', outline: 'none' };
  const labelStyle = { fontSize: 13, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6, display: 'block' };

  const submit = () => {
    onDone({ provider: provObj ? provObj.short : form.provider, cat: form.cat, sub: form.sub || (provObj && provObj.sub) || catName(form.cat), date: form.date, amount: parseFloat(form.amount), invoice: form.invoice || 'INV-NEW', invoiceId: (prefill && prefill.kind && prefill.id) || null, file: (prefill && prefill.kind) ? null : file });
    setStep(2);
  };

  const pickFile = async (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    setUping(true);
    try { const r = await Store.uploadFile(f); setFile({ name: r.name, url: r.url }); }
    catch (err) { setFile({ name: f.name, url: null }); }
    setUping(false);
  };

  return (
    <Modal open={open} onClose={onClose} width={540} title={step === 2 ? null : 'Log a claim'} sub={step === 2 ? null : step === 0 ? 'Step 1 of 2 · the details' : 'Step 2 of 2 · check it over'}>
      {step < 2 && (
        <div style={{ display: 'flex', gap: 6, marginBottom: 22 }}>
          {[0, 1].map((s) => <div key={s} style={{ flex: 1, height: 4, borderRadius: 99, background: s <= step ? 'var(--primary)' : 'var(--surface-2)', transition: 'background .3s' }} />)}
        </div>
      )}

      {step === 0 && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div>
            <label style={labelStyle}>Who did you buy the support from?</label>
            <select style={inputStyle} value={form.provider} onChange={(e) => { const p = Store.doc.providers.find((x) => x.name === e.target.value); set('provider', e.target.value); if (p) { set('cat', p.cat); set('sub', p.sub); } }}>
              <option value="">Choose a provider…</option>
              {Store.doc.providers.map((p) => <option key={p.id} value={p.name}>{p.name}</option>)}
            </select>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={labelStyle}>Budget category</label>
              <select style={inputStyle} value={form.cat} onChange={(e) => set('cat', e.target.value)}>
                <option value="">Choose…</option>
                {Store.doc.budget.map((b) => <option key={b.key} value={b.key}>{b.name}</option>)}
              </select>
            </div>
            <div>
              <label style={labelStyle}>Support date</label>
              <input type="date" style={inputStyle} value={form.date} onChange={(e) => set('date', e.target.value)} />
            </div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={labelStyle}>Amount (inc. GST)</label>
              <div style={{ position: 'relative' }}>
                <span style={{ position: 'absolute', left: 13, top: 11, color: 'var(--ink-3)', fontSize: 14.5 }}>$</span>
                <input type="number" placeholder="0.00" style={{ ...inputStyle, paddingLeft: 24 }} value={form.amount} onChange={(e) => set('amount', e.target.value)} />
              </div>
            </div>
            <div>
              <label style={labelStyle}>Invoice / receipt no.</label>
              <input placeholder="e.g. INV-2310" style={inputStyle} value={form.invoice} onChange={(e) => set('invoice', e.target.value)} />
            </div>
          </div>
          <label style={{ display: 'flex', gap: 11, alignItems: 'center', padding: '13px 15px', border: '1.5px dashed ' + (file && file.url ? 'var(--good)' : 'var(--line-2)'), borderRadius: 12, cursor: 'pointer', color: file ? 'var(--ink)' : 'var(--ink-2)', fontSize: 13.5 }}>
            <input type="file" accept=".pdf,.png,.jpg,.jpeg,.heic,.webp,.gif" style={{ display: 'none' }} onChange={pickFile} />
            <Icons.paperclip size={18} />
            <span style={{ flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
              {uping ? 'Storing on your NAS…' : file ? (file.url ? `${file.name} — stored ✓` : `${file.name} — couldn't store the file (details still saved)`) : 'Attach the invoice file'}
            </span>
            <span style={{ color: 'var(--primary-ink)', fontWeight: 600 }}>{file ? 'Change' : 'Browse'}</span>
          </label>
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10, marginTop: 4 }}>
            <Button variant="ghost" onClick={onClose}>Cancel</Button>
            <Button disabled={!canNext} icon={Icons.chevR} iconRight onClick={() => setStep(1)} style={{ opacity: canNext ? 1 : 0.5, pointerEvents: canNext ? 'auto' : 'none' }}>Review</Button>
          </div>
        </div>
      )}

      {step === 1 && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <Card pad={18} style={{ background: 'var(--surface-2)', border: 'none' }}>
            {[
              ['Provider', form.provider],
              ['Category', catName(form.cat)],
              ['Support date', fmtDate(form.date)],
              ['Invoice', form.invoice || '—'],
            ].map(([k, v]) => (
              <div key={k} style={{ display: 'flex', justifyContent: 'space-between', padding: '7px 0', fontSize: 14, borderBottom: '1px solid var(--line)' }}>
                <span style={{ color: 'var(--ink-2)' }}>{k}</span><span style={{ fontWeight: 600 }}>{v}</span>
              </div>
            ))}
            <div style={{ display: 'flex', justifyContent: 'space-between', paddingTop: 12, fontSize: 17 }}>
              <span style={{ fontWeight: 600 }}>Claim amount</span><span style={{ fontWeight: 700, color: 'var(--primary)' }}>{fmtMoney(parseFloat(form.amount || 0), 2)}</span>
            </div>
          </Card>
          <Note tone="info" icon="info">This will come out of your <b>{catName(form.cat)}</b> budget, which has <b>{fmtMoney((Store.doc.budget.find((b) => b.key === form.cat) || {}).remaining || 0)}</b> left. Once sent, the NDIS usually pays you within 2–3 days.</Note>
          <div style={{ display: 'flex', justifyContent: 'space-between', gap: 10, marginTop: 4 }}>
            <Button variant="ghost" icon={Icons.chevL} onClick={() => setStep(0)}>Back</Button>
            <Button icon={Icons.send} onClick={submit}>Submit claim</Button>
          </div>
        </div>
      )}

      {step === 2 && (
        <div style={{ textAlign: 'center', padding: '14px 10px 6px' }}>
          <div style={{ width: 78, height: 78, borderRadius: '50%', background: 'var(--good-soft)', color: 'var(--good)', display: 'grid', placeItems: 'center', margin: '0 auto 18px', animation: 'pop .4s ease both' }}>
            <Icons.check size={42} stroke={2.4} />
          </div>
          <h3 style={{ margin: '0 0 8px', fontFamily: 'var(--serif)', fontWeight: 500, fontSize: 25 }}>Claim sent 🎉</h3>
          <p style={{ margin: '0 auto 22px', color: 'var(--ink-2)', fontSize: 14.5, maxWidth: 380, lineHeight: 1.5 }}>
            {fmtMoney(parseFloat(form.amount || 0), 2)} to {form.provider} has been recorded. {file && file.url ? 'The invoice file is stored in your vault for the 5 years the NDIS asks for.' : 'Now submit it in the NDIS myplace portal if you haven\u2019t already \u2014 and mark it paid here when the money lands.'}
          </p>
          <div style={{ display: 'flex', gap: 10, justifyContent: 'center' }}>
            <Button variant="ghost" onClick={onClose}>Done</Button>
            <Button onClick={() => { setStep(0); setForm({ ...blank }); }} icon={Icons.plus}>Log another</Button>
          </div>
        </div>
      )}
    </Modal>
  );
}

// ══════════════════════════════════════════════════════════════════
// INVOICES VAULT
// ══════════════════════════════════════════════════════════════════
function Invoices({ arg, go, clearArg }) {
  const S = useHaven();
  const invs = S.doc.invoices;
  const [filter, setFilter] = uS('all');
  const [q, setQ] = uS('');
  const [adding, setAdding] = uS(false);
  const [editingInv, setEditingInv] = uS(null);

  uE(() => { if (arg === 'add') { setAdding(true); clearArg && clearArg(); } }, [arg]);

  const waiting = invs.filter((i) => !i.claimed);
  const waitingTotal = waiting.reduce((s, i) => s + i.amount, 0);
  const filtered = invs.filter((i) =>
    (filter === 'all' ? true : filter === 'waiting' ? !i.claimed : !!i.claimed) &&
    (q === '' || (i.provider + ' ' + i.id).toLowerCase().includes(q.toLowerCase())));

  return (
    <div className="fade-in">
      <PageHead
        title="Invoice vault"
        sub={<>Every invoice and receipt, kept safe and searchable. The NDIS asks you to hold these for 5 years — Haven does that automatically.</>}
        right={<Button icon={Icons.upload} onClick={() => setAdding(true)}>Add invoice</Button>}
      />

      {waiting.length > 0 && (
        <div style={{ marginBottom: 18 }}>
          <Note tone="amber" icon="receipt">
            <b>{waiting.length} invoices</b> ({fmtMoney(waitingTotal, 2)}) are waiting to be claimed.{' '}
            <a style={{ color: 'var(--primary-ink)', fontWeight: 600, cursor: 'pointer' }} onClick={() => setFilter('waiting')}>Show them →</a>
          </Note>
        </div>
      )}

      <div style={{ display: 'flex', gap: 12, marginBottom: 18, alignItems: 'center', flexWrap: 'wrap' }}>
        <div style={{ position: 'relative', flex: 1, minWidth: 220, maxWidth: 340 }}>
          <span style={{ position: 'absolute', left: 12, top: 10, color: 'var(--ink-3)' }}><Icons.search size={18} /></span>
          <input placeholder="Search provider or invoice no." value={q} onChange={(e) => setQ(e.target.value)} style={{ width: '100%', padding: '9px 13px 9px 38px', fontSize: 14, fontFamily: 'var(--sans)', border: '1px solid var(--line-2)', borderRadius: 11, outline: 'none', background: 'var(--surface)', color: 'var(--ink)' }} />
        </div>
        <div style={{ display: 'flex', gap: 6, background: 'var(--surface-2)', padding: 4, borderRadius: 11 }}>
          {[['all', 'All'], ['waiting', 'To claim'], ['claimed', 'Claimed']].map(([k, l]) => (
            <button key={k} onClick={() => setFilter(k)} style={{ border: 'none', background: filter === k ? 'var(--surface)' : 'transparent', boxShadow: filter === k ? 'var(--shadow-sm)' : 'none', color: filter === k ? 'var(--ink)' : 'var(--ink-2)', fontWeight: 600, fontSize: 13.5, padding: '7px 14px', borderRadius: 8 }}>{l}</button>
          ))}
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: 14 }}>
        {filtered.length === 0 && <div style={{ gridColumn: '1 / -1', padding: 36, textAlign: 'center', color: 'var(--ink-3)', fontSize: 14 }}>No invoices here yet — they'll appear as you add them.</div>}
        {filtered.map((inv) => (
          <Card key={inv.id} pad={0} hover style={{ overflow: 'hidden' }}>
            {/* file preview */}
            <div style={{ height: 116, background: `repeating-linear-gradient(135deg, ${catSoft(inv.cat)}, ${catSoft(inv.cat)} 11px, var(--surface) 11px, var(--surface) 22px)`, position: 'relative', display: 'grid', placeItems: 'center', borderBottom: '1px solid var(--line)' }}>
              {inv.file && inv.file.url ? (
                <a href={inv.file.url} target="_blank" rel="noopener" style={{ background: 'var(--surface)', borderRadius: 10, padding: '8px 12px', boxShadow: 'var(--shadow-sm)', display: 'flex', alignItems: 'center', gap: 7, color: 'var(--primary-ink)', textDecoration: 'none', maxWidth: '85%' }}>
                  <Icons.doc size={17} /><span style={{ fontSize: 12.5, fontWeight: 600, fontFamily: 'ui-monospace, monospace', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{inv.file.name}</span>
                </a>
              ) : (
                <label style={{ background: 'var(--surface)', borderRadius: 10, padding: '8px 12px', boxShadow: 'var(--shadow-sm)', display: 'flex', alignItems: 'center', gap: 7, color: 'var(--primary-ink)', maxWidth: '85%', cursor: 'pointer' }}>
                  <input type="file" accept=".pdf,.png,.jpg,.jpeg,.heic,.webp,.gif" style={{ display: 'none' }} onChange={async (e) => { const fl = e.target.files && e.target.files[0]; e.target.value = ''; if (!fl) return; try { const r = await Store.uploadFile(fl); S.listPatch('invoices', inv.id, { file: { name: r.name, url: r.url } }); } catch (err) { alert("Couldn't store the file — is the NAS reachable?"); } }} />
                  <Icons.paperclip size={15} /><span style={{ fontSize: 12.5, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>attach the file…</span>
                </label>
              )}
              <span style={{ position: 'absolute', top: 10, right: 10 }}>
                {inv.claimed
                  ? <Pill color="var(--good)" bg="var(--good-soft)"><Icons.check size={12} />Claimed</Pill>
                  : <Pill color="var(--amber-ink)" bg="var(--amber-soft)"><Icons.clock size={12} />To claim</Pill>}
              </span>
            </div>
            <div style={{ padding: 15 }}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', columnGap: 8, alignItems: 'start' }}>
                <span style={{ fontSize: 14.5, fontWeight: 600, lineHeight: 1.25 }}>{inv.provider}</span>
                <span style={{ fontSize: 14.5, fontWeight: 700, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>{fmtMoney(inv.amount, 2)}</span>
              </div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-3)', margin: '6px 0 12px', display: 'flex', alignItems: 'center', gap: 6 }}>
                <span style={{ width: 8, height: 8, borderRadius: 2, background: catColor(inv.cat), flexShrink: 0 }} />{fmtDateShort(inv.date)} · {inv.id}
              </div>
              <div style={{ display: 'flex', gap: 8 }}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  {!inv.claimed
                    ? <Button size="sm" full icon={Icons.send} onClick={() => go('claims', inv)}>Claim this</Button>
                    : <Button size="sm" full variant="ghost" icon={Icons.checkCircle} onClick={() => go('claims')}>View claim</Button>}
                </div>
                <button title="Edit details" onClick={() => setEditingInv(inv)} style={{ width: 34, borderRadius: 10, border: '1px solid var(--line-2)', background: 'transparent', color: 'var(--ink-3)', display: 'grid', placeItems: 'center', flexShrink: 0 }}><Icons.pencil size={15} /></button>
                <DangerBtn label="" title="Remove this record from the vault" onConfirm={() => S.deleteInvoice(inv.id)} />
              </div>
            </div>
          </Card>
        ))}
      </div>

      <AddInvoice open={adding} onClose={() => setAdding(false)} onDone={(inv) => S.addInvoice(inv)} />
      <EditInvoice inv={editingInv} onClose={() => setEditingInv(null)} />
    </div>
  );
}

// ── Add an invoice: real file upload + your details ─────────────────
function AddInvoice({ open, onClose, onDone }) {
  const [phase, setPhase] = uS('drop'); // drop | up | read | form
  const [file, setFile] = uS(null);
  const skipRef = React.useRef(false);
  const blankInv = { id: '', provider: '', cat: 'core', date: '', amount: '' };
  const [f, setF] = uS(blankInv);
  uE(() => { if (open) { setPhase('drop'); setFile(null); setF({ ...blankInv, date: TODAY.toISOString().slice(0, 10) }); } }, [open]);

  const inputStyle = { width: '100%', padding: '11px 13px', fontSize: 14.5, fontFamily: 'var(--sans)', border: '1px solid var(--line-2)', borderRadius: 11, background: 'var(--surface)', color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' };
  const labelStyle = { fontSize: 13, fontWeight: 600, color: 'var(--ink-2)', marginBottom: 6, display: 'block' };
  const set = (k, v) => setF((x) => ({ ...x, [k]: v }));

  const handleFile = async (fl) => {
    if (!fl) return;
    setPhase('up');
    let stored;
    try { const r = await Store.uploadFile(fl); stored = { name: r.name, url: r.url }; }
    catch (e) { stored = { name: fl.name, url: null }; }
    setFile(stored);
    // read the file on this computer and take a best guess at the fields
    skipRef.current = false;
    setPhase('read');
    let guess = null;
    try { guess = await extractInvoiceFields(fl); } catch (e) {}
    if (skipRef.current) return;   // user chose to type instead
    if (guess) setF((x) => ({ ...x, provider: guess.provider || x.provider, cat: guess.cat || x.cat, amount: guess.amount != null ? String(guess.amount) : x.amount, id: guess.id || x.id, date: guess.date || x.date, _guessed: true }));
    setPhase('form');
  };

  const canSave = f.provider && f.amount;
  const save = () => {
    onDone({ id: f.id || ('R-' + Date.now().toString(36).toUpperCase()), provider: f.provider, cat: f.cat, date: f.date, amount: parseFloat(f.amount) || 0, kind: 'invoice', claimed: null, file });
    onClose();
  };

  return (
    <Modal open={open} onClose={onClose} width={520} title="Add an invoice" sub="The file is kept on your NAS, with the details beside it.">
      {phase === 'drop' && (
        <div>
          <label
            onDragOver={(e) => e.preventDefault()}
            onDrop={(e) => { e.preventDefault(); handleFile(e.dataTransfer.files && e.dataTransfer.files[0]); }}
            style={{ display: 'block', border: '2px dashed var(--line-2)', borderRadius: 16, padding: '46px 24px', textAlign: 'center', cursor: 'pointer', background: 'var(--surface-2)' }}>
            <input type="file" accept=".pdf,.png,.jpg,.jpeg,.heic,.webp,.gif" style={{ display: 'none' }} onChange={(e) => handleFile(e.target.files && e.target.files[0])} />
            <div style={{ color: 'var(--primary)', marginBottom: 12 }}><Icons.upload size={38} /></div>
            <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 5 }}>Drop a PDF or photo here</div>
            <div style={{ fontSize: 13.5, color: 'var(--ink-2)' }}>or click to browse</div>
          </label>
          <div style={{ textAlign: 'center', marginTop: 14 }}>
            <a style={{ color: 'var(--primary-ink)', fontWeight: 600, fontSize: 13.5, cursor: 'pointer' }} onClick={() => setPhase('form')}>No file? Enter the details only →</a>
          </div>
        </div>
      )}
      {phase === 'up' && (
        <div style={{ textAlign: 'center', padding: '40px 24px' }}>
          <div style={{ color: 'var(--primary)', marginBottom: 16, animation: 'pop .4s ease both' }}><Icons.upload size={38} /></div>
          <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 6 }}>Storing on your NAS…</div>
          <div style={{ height: 5, background: 'var(--surface-2)', borderRadius: 99, marginTop: 22, overflow: 'hidden' }}>
            <div style={{ height: '100%', background: 'var(--primary)', borderRadius: 99, animation: 'fillbar 1.2s ease both' }} />
          </div>
          <style>{`@keyframes fillbar{from{width:0}to{width:100%}}`}</style>
        </div>
      )}
      {phase === 'read' && (
        <div style={{ textAlign: 'center', padding: '36px 24px' }}>
          <div style={{ color: 'var(--primary)', marginBottom: 16, animation: 'pop .4s ease both' }}><Icons.sparkles size={38} /></div>
          <div style={{ fontWeight: 600, fontSize: 16, marginBottom: 6 }}>Reading the invoice…</div>
          <div style={{ fontSize: 13.5, color: 'var(--ink-2)', maxWidth: 340, margin: '0 auto' }}>This happens on your computer — the file isn't sent anywhere. The first time takes a minute while the reader downloads.</div>
          <div style={{ marginTop: 18 }}>
            <a style={{ color: 'var(--primary-ink)', fontWeight: 600, fontSize: 13.5, cursor: 'pointer' }} onClick={() => { skipRef.current = true; setPhase('form'); }}>Skip — I'll type the details</a>
          </div>
        </div>
      )}
      {phase === 'form' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {file && !file.url && <Note tone="amber" icon="alert"><b>{file.name}</b> couldn't be stored (NAS not reachable right now) — the details below will still be saved.</Note>}
          {f._guessed
            ? <Note tone="primary" icon="sparkles">Haven read the file and took its best guess — <b>check every field</b> before saving.</Note>
            : (file && file.url && <Note tone="good" icon="checkCircle"><b>{file.name}</b> is stored safely on the NAS. Now the details:</Note>)}
          <div>
            <label style={labelStyle}>Provider</label>
            <input list="haven-prov-list" style={inputStyle} placeholder="Start typing…" value={f.provider}
              onChange={(e) => { set('provider', e.target.value); const p = Store.doc.providers.find((x) => x.name === e.target.value); if (p) set('cat', p.cat); }} />
            <datalist id="haven-prov-list">{Store.doc.providers.map((p) => <option key={p.id} value={p.name} />)}</datalist>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={labelStyle}>Budget category</label>
              <select style={inputStyle} value={f.cat} onChange={(e) => set('cat', e.target.value)}>
                {Store.doc.budget.map((b) => <option key={b.key} value={b.key}>{b.name}</option>)}
              </select>
            </div>
            <div>
              <label style={labelStyle}>Invoice date</label>
              <input type="date" style={inputStyle} value={f.date} onChange={(e) => set('date', e.target.value)} />
            </div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
            <div>
              <label style={labelStyle}>Amount (inc. GST)</label>
              <div style={{ position: 'relative' }}>
                <span style={{ position: 'absolute', left: 13, top: 11, color: 'var(--ink-3)', fontSize: 14.5 }}>$</span>
                <input type="number" placeholder="0.00" style={{ ...inputStyle, paddingLeft: 24 }} value={f.amount} onChange={(e) => set('amount', e.target.value)} />
              </div>
            </div>
            <div>
              <label style={labelStyle}>Invoice / receipt no.</label>
              <input placeholder="e.g. INV-2310" style={inputStyle} value={f.id} onChange={(e) => set('id', e.target.value)} />
            </div>
          </div>
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
            <Button variant="ghost" onClick={onClose}>Cancel</Button>
            <Button icon={Icons.check} disabled={!canSave} onClick={save} style={{ opacity: canSave ? 1 : 0.5, pointerEvents: canSave ? 'auto' : 'none' }}>Save to vault</Button>
          </div>
        </div>
      )}
    </Modal>
  );
}

Object.assign(window, { Claims, Invoices, catName, catColor, catSoft });
