// Needs Review queue. Lists Plaid transactions from management-flagged
// accounts that don't yet have a house + final category assigned. Each
// row shows house + category dropdowns side-by-side with a single Confirm
// button — no detail-panel two-step. Category is pre-filled with whatever
// Plaid's auto-categorization landed on; user can override before confirm.
//
// On confirm: the row fades + slides out, then store.reloadTransactions()
// updates the rest of the app (P&Ls, sidebar badge).

function NeedsReviewPage({ store }) {
  const [rows, setRows]               = React.useState(null);   // null = loading
  const [forms, setForms]             = React.useState({});      // {id: {house_id, category}}
  const [pendingIds, setPendingIds]   = React.useState(() => new Set());
  const [fadingIds, setFadingIds]     = React.useState(() => new Set());
  const [errorByRow, setErrorByRow]   = React.useState({});

  const refresh = React.useCallback(async () => {
    const { data, error } = await window.db.from('transactions')
      .select('id, date, description, amount, type, category, plaid_accounts(name, mask)')
      .eq('status', 'needs_review')
      .order('date', { ascending: false });
    if (error) { console.error('needs-review fetch:', error); setRows([]); return; }
    setRows(data);
    setForms(prev => {
      const next = {};
      for (const r of data) next[r.id] = prev[r.id] || { house_id: '', category: r.category || '' };
      return next;
    });
  }, []);

  React.useEffect(() => { refresh(); }, [refresh]);

  const updateForm = (id, patch) => setForms(prev => ({ ...prev, [id]: { ...prev[id], ...patch } }));

  const onConfirm = async (id) => {
    const form = forms[id];
    if (!form?.house_id || !form?.category) return;

    setErrorByRow(prev => { const n = { ...prev }; delete n[id]; return n; });
    setPendingIds(prev => new Set(prev).add(id));

    try {
      const r = await fetch('/api/plaid/confirm-transaction', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ id, house_id: houseUuid(form.house_id), category: form.category }),
      });
      if (!r.ok) {
        const detail = await r.json().catch(() => ({}));
        throw new Error(detail.error || ('HTTP ' + r.status));
      }

      // Fade out, then drop from local list and refresh store-wide totals.
      setFadingIds(prev => new Set(prev).add(id));
      setTimeout(() => {
        setRows(prev => prev.filter(x => x.id !== id));
        setFadingIds(prev => { const n = new Set(prev); n.delete(id); return n; });
        store.reloadTransactions();
      }, 240);
    } catch (e) {
      setErrorByRow(prev => ({ ...prev, [id]: e.message }));
    } finally {
      setPendingIds(prev => { const n = new Set(prev); n.delete(id); return n; });
    }
  };

  return (
    <>
      <Topbar
        title="Needs Review"
        subtitle="Transactions from management accounts — assign a property and category to confirm them into a P&L"
      />
      <div className="content" style={{ display: 'grid', gap: 16 }}>
        {rows === null ? (
          <div className="card card-pad-lg" style={{ color: 'var(--text-tertiary)' }}>Loading…</div>
        ) : rows.length === 0 ? (
          <NeedsReviewEmpty/>
        ) : (
          <div className="card" style={{ overflow: 'hidden' }}>
            <div style={{
              padding: '10px 18px', borderBottom: '1px solid var(--border)',
              background: 'var(--bg-sunken)',
              display: 'grid',
              gridTemplateColumns: '92px 1fr 110px 200px 220px 110px',
              gap: 12,
              fontSize: 11, letterSpacing: 0.5, textTransform: 'uppercase', color: 'var(--text-tertiary)',
            }}>
              <div>Date</div>
              <div>Description · source</div>
              <div style={{ textAlign: 'right' }}>Amount</div>
              <div>Property</div>
              <div>Category</div>
              <div></div>
            </div>
            {rows.map(row => (
              <NeedsReviewRow
                key={row.id}
                row={row}
                houses={store.houses}
                form={forms[row.id]}
                pending={pendingIds.has(row.id)}
                fading={fadingIds.has(row.id)}
                error={errorByRow[row.id]}
                onChange={(patch) => updateForm(row.id, patch)}
                onConfirm={() => onConfirm(row.id)}
              />
            ))}
          </div>
        )}
      </div>
    </>
  );
}

function NeedsReviewRow({ row, houses, form, pending, fading, error, onChange, onConfirm }) {
  const acct = row.plaid_accounts;
  const canConfirm = !!(form?.house_id && form?.category) && !pending && !fading;
  const isExpense = row.type === 'expense';

  return (
    <div style={{
      padding: '12px 18px',
      borderBottom: '1px solid var(--border)',
      display: 'grid',
      gridTemplateColumns: '92px 1fr 110px 200px 220px 110px',
      gap: 12,
      alignItems: 'center',
      transition: 'opacity 220ms ease, transform 220ms ease',
      opacity: fading ? 0 : 1,
      transform: fading ? 'translateX(-12px)' : 'translateX(0)',
      pointerEvents: fading ? 'none' : 'auto',
    }}>
      <div className="small tabular muted">{fmtDate(row.date)}</div>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontWeight: 500, fontSize: 14, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
          {row.description}
        </div>
        <div className="xs muted" style={{ marginTop: 2 }}>
          {acct?.name} ••{acct?.mask}
        </div>
      </div>
      <div className="tabular" style={{ textAlign: 'right', fontWeight: 500, fontSize: 14, color: isExpense ? 'var(--expense)' : 'var(--income)' }}>
        {isExpense ? '−' : '+'}{fmt$(row.amount)}
      </div>
      <select
        value={form?.house_id || ''}
        onChange={e => onChange({ house_id: e.target.value })}
        disabled={pending || fading}
        style={selectStyle}
      >
        <option value="">— Choose property —</option>
        {houses.map(h => <option key={h.id} value={h.id}>{h.name}</option>)}
      </select>
      <select
        value={form?.category || ''}
        onChange={e => onChange({ category: e.target.value })}
        disabled={pending || fading}
        style={selectStyle}
      >
        <option value="">— Choose category —</option>
        <optgroup label={isExpense ? 'Expenses' : 'Other'}>
          {CATEGORIES.expense.map(c => <option key={c} value={c}>{c}</option>)}
        </optgroup>
        <optgroup label={isExpense ? 'Other' : 'Income'}>
          {CATEGORIES.income.map(c => <option key={c} value={c}>{c}</option>)}
        </optgroup>
      </select>
      <button
        className="btn accent"
        onClick={onConfirm}
        disabled={!canConfirm}
        style={{ justifySelf: 'end' }}
      >
        {pending ? 'Saving…' : 'Confirm'}
      </button>
      {error && (
        <div style={{ gridColumn: '1 / -1', color: 'var(--expense)', fontSize: 12, marginTop: 4 }}>
          {error}
        </div>
      )}
    </div>
  );
}

function NeedsReviewEmpty() {
  return (
    <div className="card card-pad-lg" style={{ display: 'grid', placeItems: 'center', padding: '64px 24px', gap: 14 }}>
      <div style={{
        width: 60, height: 60, borderRadius: 16,
        background: 'var(--accent-soft)', color: 'var(--accent)',
        display: 'grid', placeItems: 'center',
      }}>
        {React.cloneElement(Icon.check, { style: { width: 30, height: 30 } })}
      </div>
      <div style={{ textAlign: 'center' }}>
        <div className="serif" style={{ fontSize: 24, fontWeight: 400, letterSpacing: '-0.01em' }}>All caught up</div>
        <div className="small muted" style={{ marginTop: 6 }}>
          Nothing in the review queue. New management-account transactions will land here automatically.
        </div>
      </div>
    </div>
  );
}

const selectStyle = {
  padding: '6px 10px',
  borderRadius: 6,
  border: '1px solid var(--border)',
  background: 'var(--bg-elev)',
  color: 'var(--text)',
  fontSize: 13,
  cursor: 'pointer',
  width: '100%',
};

Object.assign(window, { NeedsReviewPage });
