// Positions tab + Orders tab

const POS_CAT_COLOR = { FX: '#3B82F6', Metals: '#E0A21A', Energy: '#E2563B', Indices: '#8B5CF6', Crypto: '#F7931A' };
function posPair(sym) {
  return sym.length === 6 && sym.match(/^[A-Z]{6}$/) ? sym.slice(0, 3) + '/' + sym.slice(3) : sym;
}

// compact 3-part price
function PPx({ value, inst, size = 13, color }) {
  const { base, pips, frac } = splitPip(value, inst.digits, inst.pipDigits);
  return (
      // A 3-part price is three ADJACENT spans, which is exactly the shape
      // RTL reorders: 1.08|57|4 renders as 4|57|1.08 — an unreadable price,
      // not a cosmetic difference. Pinning the wrapper to LTR keeps the
      // parts in order; the surrounding row still mirrors normally (ID5).
    <span style={{ display: 'inline-flex', alignItems: 'flex-end', direction: 'ltr', unicodeBidi: 'isolate', color, fontVariantNumeric: 'tabular-nums', lineHeight: 1 }}>
      <span style={{ fontSize: Math.round(size * 0.8), fontWeight: 600, opacity: 0.72 }}>{base}</span>
      <span style={{ fontSize: size, fontWeight: 700 }}>{pips}</span>
      {frac && <span style={{ fontSize: Math.round(size * 0.6), fontWeight: 600, alignSelf: 'flex-start', opacity: 0.72 }}>{frac}</span>}
    </span>
  );
}

function SideTag({ side, vol, theme }) {
  const isBuy = side === 'buy';
  return (
    <span style={{
      padding: '1.5px 6px', borderRadius: 5, fontSize: 10.5, fontWeight: 700,
      textTransform: 'uppercase', letterSpacing: 0.3,
      color: isBuy ? theme.buy : theme.sell, background: isBuy ? theme.buyBg : theme.sellBg,
      fontVariantNumeric: 'tabular-nums', flexShrink: 0,
    }}>{isBuy ? t('common.side.buy') : t('common.side.sell')} {vol.toFixed(2)}</span>
  );
}

// OriginTag — PD5 attribution, deferred here from P2 (docs/public-api.md §6 P3).
//
// Nothing renders for a terminal-placed row: the wire omits `origin` for
// TERMINAL and for every pre-P2 row, so the test is presence and an unbadged
// row means "you placed this". Badging all of them would be noise over the two
// that matter.
//
// The label is the token's own name — arbitrary user text in an unknown
// script — so it sits in a <bdi>, or an Arabic bot name inside an LTR row (and
// "vwap-bot" inside an Arabic one) reorders against the row around it. The
// channel word renders from the CODE (FR4), never from the wire string.
function OriginTag({ row, theme }) {
  if (!row || !row.origin) return null;
  const channel = tCode('origin', row.origin);
  const label = row.originLabel || channel;
  return (
    <span
      title={row.originLabel
        ? t('agent.origin.titleLabelled', { label: row.originLabel, channel })
        : t('agent.origin.titleBare', { channel })}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 3, flexShrink: 1, minWidth: 0,
        padding: '1.5px 6px', borderRadius: 5, maxWidth: 104,
        background: `${theme.accent}1F`, border: `0.5px solid ${theme.accent}55`,
      }}
    >
      <span style={{ width: 4, height: 4, borderRadius: 2, background: theme.accent, flexShrink: 0 }} />
      <bdi style={{
        fontSize: 10, fontWeight: 700, color: theme.accent,
        overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
      }}>{label}</bdi>
    </span>
  );
}

// One ticket. showSymbol → flat list (leads with dot + symbol); else inside a Net group.
function TicketLine({ pos, inst, priceState, theme, showSymbol, onTap, last }) {
  const pl = computePL(pos, priceState.bid, priceState.ask);
  const isProfit = pl >= 0;
  const curPrice = pos.side === 'buy' ? priceState.bid : priceState.ask;
  const c = POS_CAT_COLOR[inst.cat] || theme.accent;
  const meta = (label, val, col) => (
    <span style={{ color: theme.textTer, fontWeight: 600 }}>{label} <span style={{ color: col || theme.textSec, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{val}</span></span>
  );
  return (
    <div
      onClick={() => onTap(pos)}
      style={{
        padding: showSymbol ? '11px 16px' : '9px 16px 9px 28px', cursor: 'pointer',
        borderBottom: last ? 'none' : `0.5px solid ${theme.border}`,
      }}
    >
      {/* line 1 */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
        {showSymbol && <div style={{ width: 7, height: 7, borderRadius: 4, background: c, flexShrink: 0 }} />}
        {showSymbol && <span style={{ fontSize: 14, fontWeight: 700, color: theme.text, letterSpacing: -0.2 }}>{posPair(pos.sym)}</span>}
        <SideTag side={pos.side} vol={pos.vol} theme={theme} />
        <span style={{ fontSize: 11, color: theme.textTer, fontVariantNumeric: 'tabular-nums' }}>#{pos.ticket}</span>
        <OriginTag row={pos} theme={theme} />
        <span style={{ marginInlineStart: 'auto', fontSize: 14, fontWeight: 700, color: isProfit ? theme.buy : theme.sell, fontVariantNumeric: 'tabular-nums' }}>{fmtMoney(pl)}</span>
      </div>
      {/* line 2 */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 4, fontSize: 11, color: theme.textSec, flexWrap: 'wrap' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
          <PPx value={pos.openPrice} inst={inst} size={12} color={theme.textSec} />
          <svg width="9" height="7" viewBox="0 0 10 8" style={{ opacity: 0.5 }}><path d="M1 4h8M6 1l3 3-3 3" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" fill="none"/></svg>
          <PPx value={curPrice} inst={inst} size={12} color={theme.text} />
        </span>
        <span style={{ color: theme.textTer }}>{pos.openTime}</span>
        <span style={{ marginInlineStart: 'auto', display: 'flex', gap: 10 }}>
          {meta(t('common.takeProfitShort'), pos.tp ? fmtPrice(pos.tp, inst.digits) : '—', pos.tp ? theme.buy : theme.textTer)}
          {meta(t('common.stopLossShort'), pos.sl ? fmtPrice(pos.sl, inst.digits) : '—', pos.sl ? theme.sell : theme.textTer)}
        </span>
      </div>
    </div>
  );
}

// Net (exposure) group — aggregates all tickets of one symbol
function NetGroup({ sym, group, prices, theme, expanded, onToggle, onTapTicket }) {
  const inst = INSTRUMENTS.find(i => i.sym === sym);
  const ps = prices[sym];
  if (!inst || !ps) return null;
  const netVol = group.reduce((s, p) => s + (p.side === 'buy' ? p.vol : -p.vol), 0);
  const netSide = netVol >= 0 ? 'buy' : 'sell';
  const pl = group.reduce((s, p) => s + computePL(p, ps.bid, ps.ask), 0);
  const isProfit = pl >= 0;
  const c = POS_CAT_COLOR[inst.cat] || theme.accent;
  return (
    <div style={{ background: theme.bgCard, borderRadius: 14, border: `0.5px solid ${theme.border}`, overflow: 'hidden', marginBottom: 10 }}>
      {/* group header */}
      <div onClick={() => onToggle(sym)} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '13px 14px', cursor: 'pointer' }}>
        <div style={{ width: 8, height: 8, borderRadius: 4, background: c, flexShrink: 0 }} />
        <span style={{ fontSize: 15, fontWeight: 700, color: theme.text, letterSpacing: -0.2 }}>{posPair(sym)}</span>
        <span style={{
          padding: '2px 7px', borderRadius: 5, fontSize: 10.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.3,
          color: netSide === 'buy' ? theme.buy : theme.sell, background: netSide === 'buy' ? theme.buyBg : theme.sellBg,
          fontVariantNumeric: 'tabular-nums',
        }}>{netSide === 'buy' ? t('common.side.buy') : t('common.side.sell')} {Math.abs(netVol).toFixed(2)}</span>
        {group.length > 1 && <span style={{ fontSize: 11, color: theme.textTer, fontWeight: 600 }}>{t('positions.net.tickets', { n: group.length })}</span>}
        <span style={{ marginInlineStart: 'auto', fontSize: 15, fontWeight: 700, color: isProfit ? theme.buy : theme.sell, fontVariantNumeric: 'tabular-nums' }}>{fmtMoney(pl)}</span>
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" style={{ transform: expanded ? 'rotate(180deg)' : 'none', transition: 'transform 180ms', flexShrink: 0 }}>
          <path d="M6 9l6 6 6-6" stroke={theme.textSec} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </div>
      {/* expanded tickets */}
      {expanded && (
        <div style={{ borderTop: `0.5px solid ${theme.border}` }}>
          {group.map((p, i) => (
            <TicketLine key={p.id} pos={p} inst={inst} priceState={ps} theme={theme} onTap={onTapTicket} last={i === group.length - 1} />
          ))}
        </div>
      )}
    </div>
  );
}

// Tap-a-position action sheet → Close / Modify (in-sheet SL/TP editor, O6)
function PositionActionSheet({ pos, prices, theme, onClose, onConfirmClose, onModify }) {
  const inst = INSTRUMENTS.find(i => i.sym === pos.sym);
  const ps = prices[pos.sym];
  const pip = inst ? Math.pow(10, -inst.pipDigits) : 0.0001;
  const rnd = v => inst ? +v.toFixed(inst.digits) : v;
  const cur0 = ps ? (pos.side === 'buy' ? ps.bid : ps.ask) : 0;
  const [editing, setEditing] = React.useState(false);
  const [tpOn, setTpOn] = React.useState(!!pos.tp);
  const [slOn, setSlOn] = React.useState(!!pos.sl);
  const [tp, setTp] = React.useState(pos.tp || rnd(cur0 + (pos.side === 'buy' ? 50 : -50) * pip));
  const [sl, setSl] = React.useState(pos.sl || rnd(cur0 - (pos.side === 'buy' ? 50 : -50) * pip));
  const [busy, setBusy] = React.useState(false);
  // { msg, detail } — FR4: `msg` renders from the reject CODE, and the
  // server's own English text is demoted to the tooltip so support can still
  // read it. `detail` is null when the server sent no text.
  const [err, setErr] = React.useState(null);
  if (!inst || !ps) return null;
  const pl = computePL(pos, ps.bid, ps.ask);
  const isProfit = pl >= 0;
  const curPrice = pos.side === 'buy' ? ps.bid : ps.ask;
  const c = POS_CAT_COLOR[inst.cat] || theme.accent;
  const estAt = level => computePL(pos, level, level);
  const save = async () => {
    if (busy) return;
    setBusy(true); setErr(null);
    const res = await onModify(pos, { sl: slOn ? sl : 0, tp: tpOn ? tp : 0 });
    setBusy(false);
    if (res.ok) onClose();
    else setErr({
      msg: res.rejectCode ? tCode('reject', res.rejectCode) : (res.error || t('positions.modify.failed')),
      detail: res.error || null,
    });
  };
  const row = (label, val, col) => (
    <div style={{ display: 'flex', justifyContent: 'space-between', padding: '9px 2px', borderBottom: `0.5px solid ${theme.border}` }}>
      <span style={{ fontSize: 13, color: theme.textSec }}>{label}</span>
      <span style={{ fontSize: 13, color: col || theme.text, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{val}</span>
    </div>
  );
  return (
    <div onClick={onClose} style={{ position: 'absolute', inset: 0, zIndex: 100, background: 'rgba(0,0,0,0.5)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)', display: 'flex', alignItems: 'flex-end', animation: 'fadeIn 180ms ease-out' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', background: theme.bgElevated, borderTopLeftRadius: 24, borderTopRightRadius: 24, padding: '12px 16px 28px', borderTop: `0.5px solid ${theme.border}`, animation: 'slideUp 280ms cubic-bezier(0.2,0.9,0.3,1.05)' }}>
        <div style={{ width: 36, height: 5, borderRadius: 3, background: theme.borderStrong, margin: '0 auto 14px' }} />
        {/* header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
          <div style={{ width: 34, height: 34, borderRadius: 17, background: `${c}22`, border: `1.5px solid ${c}`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <div style={{ width: 10, height: 10, borderRadius: 5, background: c }} />
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
              <span style={{ fontSize: 16, fontWeight: 700, color: theme.text, letterSpacing: -0.2 }}>{posPair(pos.sym)}</span>
              <SideTag side={pos.side} vol={pos.vol} theme={theme} />
              <OriginTag row={pos} theme={theme} />
            </div>
            <div style={{ fontSize: 11.5, color: theme.textTer, marginTop: 2, fontVariantNumeric: 'tabular-nums' }}>#{pos.ticket} · {pos.openTime}</div>
          </div>
          <div style={{ textAlign: 'end' }}>
            <div style={{ fontSize: 18, fontWeight: 700, color: isProfit ? theme.buy : theme.sell, fontVariantNumeric: 'tabular-nums' }}>{fmtMoney(pl)}</div>
          </div>
        </div>
        <div style={{ padding: '2px 0 16px' }}>
          {row(t('common.openPrice'), fmtPrice(pos.openPrice, inst.digits))}
          {row(t('common.currentPrice'), fmtPrice(curPrice, inst.digits))}
          {!editing && row(t('common.takeProfit'), pos.tp ? fmtPrice(pos.tp, inst.digits) : '—', pos.tp ? theme.buy : theme.textTer)}
          {!editing && row(t('common.stopLoss'), pos.sl ? fmtPrice(pos.sl, inst.digits) : '—', pos.sl ? theme.sell : theme.textTer)}
        </div>
        {editing && (
          <div style={{ display: 'flex', gap: 10, marginBottom: 14 }}>
            <TpSlField kind="tp" on={tpOn} setOn={setTpOn} price={tp} setPrice={setTp}
              onMinus={() => setTp(rnd(tp - pip))} onPlus={() => setTp(rnd(tp + pip))}
              est={estAt(tp)} theme={theme} inst={inst} />
            <TpSlField kind="sl" on={slOn} setOn={setSlOn} price={sl} setPrice={setSl}
              onMinus={() => setSl(rnd(sl - pip))} onPlus={() => setSl(rnd(sl + pip))}
              est={estAt(sl)} theme={theme} inst={inst} />
          </div>
        )}
        {err && <div title={err.detail || undefined} style={{ marginBottom: 10, padding: '8px 12px', borderRadius: 10, background: theme.sellBg, color: theme.sell, fontSize: 12, fontWeight: 600 }}>{err.msg}</div>}
        {!editing ? (
          <div style={{ display: 'flex', gap: 10 }}>
            <div onClick={() => setEditing(true)} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.bgSubtle, color: theme.text, textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer' }}>{t('common.action.modify')}</div>
            <div onClick={() => { onConfirmClose(pos); onClose(); }} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.sell, color: '#fff', textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer', boxShadow: `0 6px 16px ${theme.sell}44` }}>
              {t('positions.action.closeAmount', { amount: fmtMoney(pl) })}
            </div>
          </div>
        ) : (
          <div style={{ display: 'flex', gap: 10 }}>
            <div onClick={() => { setEditing(false); setErr(null); }} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.bgSubtle, color: theme.text, textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer' }}>{t('common.action.back')}</div>
            <div onClick={save} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.accent, color: '#fff', textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer', opacity: busy ? 0.6 : 1, boxShadow: `0 6px 16px ${theme.accent}44` }}>
              {busy ? t('common.action.saving') : t('common.action.save')}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function PositionsTab({ positions, prices, theme, onTapPosition, account }) {
  const [mode, setMode] = React.useState('net'); // net | tickets
  const [expanded, setExpanded] = React.useState({}); // sym → bool

  const totalPL = positions.reduce((s, p) => { const ps = prices[p.sym]; return ps ? s + computePL(p, ps.bid, ps.ask) : s; }, 0);
  // Used margin is authoritative from the monolith (account.usedMargin);
  // equity is balance+credit + edge-computed floating PL (R28).
  const acct = account || { balance: 0, credit: 0, usedMargin: 0 };
  const margin = acct.usedMargin || 0;
  const equity = (acct.balance || 0) + (acct.credit || 0) + totalPL;
  const freeMargin = equity - margin;
  const isProfit = totalPL >= 0;

  // group by symbol for net mode
  const groups = {};
  for (const p of positions) { (groups[p.sym] ||= []).push(p); }
  const groupSyms = Object.keys(groups);

  const toggle = (sym) => setExpanded(e => ({ ...e, [sym]: !e[sym] }));
  // Isolated like every other money run (ID5) — a bare "$1,840.25" in RTL
  // renders as "1,840.25$", which reads as a different notation.
  const fmtUSD = (n) => bidiIsolate('$' + n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }));

  return (
    <div>
      {/* header */}
      <div style={{ padding: '8px 16px 0' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
          <div style={{ fontSize: 30, fontWeight: 700, color: theme.text, letterSpacing: -0.5 }}>{t('nav.positions')}</div>
          <div style={{ textAlign: 'end' }}>
            <span style={{ fontSize: 11, color: theme.textTer, textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: 600, marginInlineEnd: 6 }}>{t('positions.upl')}</span>
            <span style={{ fontSize: 19, fontWeight: 700, color: isProfit ? theme.buy : theme.sell, fontVariantNumeric: 'tabular-nums', letterSpacing: -0.3 }}>{fmtMoney(totalPL)}</span>
          </div>
        </div>
        {positions.length > 0 && (
          <div style={{ display: 'flex', gap: 22, marginTop: 6 }}>
            <span style={{ fontSize: 12, color: theme.textSec }}>{t('common.margin')} <span style={{ color: theme.text, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{fmtUSD(margin)}</span></span>
            <span style={{ fontSize: 12, color: theme.textSec }}>{t('common.freeMargin')} <span style={{ color: theme.text, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{fmtUSD(freeMargin)}</span></span>
          </div>
        )}
      </div>

      {positions.length > 0 ? (
        <>
          {/* Net / Positions toggle */}
          <div style={{ padding: '12px 16px 14px' }}>
            <div style={{ display: 'flex', gap: 3, padding: 3, borderRadius: 10, background: theme.bgElevated, border: `0.5px solid ${theme.border}` }}>
              {/* first element of each pair is the mode CODE, second the label */}
              {[['net', t('positions.mode.net')], ['tickets', t('positions.mode.tickets')]].map(([m, label]) => (
                <div key={m} onClick={() => setMode(m)} style={{
                  flex: 1, textAlign: 'center', padding: '8px 0', borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: 'pointer', letterSpacing: -0.1,
                  background: mode === m ? theme.text : 'transparent', color: mode === m ? theme.bg : theme.textSec, transition: 'all 140ms',
                }}>{label}</div>
              ))}
            </div>
          </div>

          {mode === 'net' ? (
            <div style={{ padding: '0 16px' }}>
              {groupSyms.map(sym => (
                <NetGroup key={sym} sym={sym} group={groups[sym]} prices={prices} theme={theme} expanded={!!expanded[sym]} onToggle={toggle} onTapTicket={onTapPosition} />
              ))}
            </div>
          ) : (
            <div style={{ background: theme.bgCard, margin: '0 16px', borderRadius: 14, border: `0.5px solid ${theme.border}`, overflow: 'hidden' }}>
              {positions.map((pos, i) => {
                const inst = INSTRUMENTS.find(in_ => in_.sym === pos.sym);
                const ps = prices[pos.sym];
                if (!inst || !ps) return null;
                return <TicketLine key={pos.id} pos={pos} inst={inst} priceState={ps} theme={theme} showSymbol onTap={onTapPosition} last={i === positions.length - 1} />;
              })}
            </div>
          )}
        </>
      ) : (
        <EmptyState theme={theme} title={t('positions.empty.title')} body={t('positions.empty.body')} />
      )}

      <div style={{ height: 100 }} />
    </div>
  );
}

// Compact pending-order row — same visual language as TicketLine.
// Market orders can pass through here transiently (in-flight / last-look
// hold) — they have no trigger price, so show their state instead of 0.
function OrderLine({ order, inst, priceState, theme, onTap, last }) {
  const isBuy = order.type.startsWith('Buy');
  const isMarket = !order.triggerPrice;
  const curPrice = isBuy ? priceState.ask : priceState.bid;
  const pip = Math.pow(10, -inst.pipDigits);
  const pipsAway = (order.triggerPrice - curPrice) / pip;
  const c = POS_CAT_COLOR[inst.cat] || theme.accent;
  return (
    <div
      onClick={() => onTap(order)}
      style={{ padding: '11px 16px', cursor: 'pointer', borderBottom: last ? 'none' : `0.5px solid ${theme.border}` }}
    >
      {/* line 1 */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
        <div style={{ width: 7, height: 7, borderRadius: 4, background: c, flexShrink: 0 }} />
        <span style={{ fontSize: 14, fontWeight: 700, color: theme.text, letterSpacing: -0.2 }}>{posPair(order.sym)}</span>
        <span style={{
          padding: '1.5px 6px', borderRadius: 5, fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.3,
          color: isBuy ? theme.buy : theme.sell, background: isBuy ? theme.buyBg : theme.sellBg, flexShrink: 0,
        }}>{t('order.type.' + order.typeCode)} {order.vol.toFixed(2)}</span>
        <span style={{ fontSize: 11, color: theme.textTer, fontVariantNumeric: 'tabular-nums' }}>#{order.ticket}</span>
        <OriginTag row={order} theme={theme} />
        <span style={{ marginInlineStart: 'auto', display: 'inline-flex', alignItems: 'flex-end' }}>
          {isMarket
            ? <span style={{ fontSize: 12, fontWeight: 700, color: theme.textSec, textTransform: 'uppercase', letterSpacing: 0.4 }}>{tCode('status', order.status)}</span>
            : <PPx value={order.triggerPrice} inst={inst} size={14} color={theme.text} />}
        </span>
      </div>
      {/* line 2 */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 4, fontSize: 11, color: theme.textSec, flexWrap: 'wrap' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: theme.textTer }}>
          {t('orders.now')}
          <PPx value={curPrice} inst={inst} size={12} color={theme.textSec} />
        </span>
        {!isMarket && <span style={{ color: theme.textSec, fontVariantNumeric: 'tabular-nums' }}>{t('orders.pipsAway', { pips: Math.abs(pipsAway).toFixed(1) })}</span>}
        <span style={{ marginInlineStart: 'auto', color: theme.textTer }}>{t('orders.exp')} <span style={{ color: theme.textSec, fontWeight: 600 }}>{tCode('tif', order.expiry)}</span></span>
      </div>
    </div>
  );
}

// Tap-an-order action sheet → Modify / Cancel
function OrderActionSheet({ order, prices, theme, onClose, onConfirmCancel, onModify }) {
  const inst = INSTRUMENTS.find(i => i.sym === order.sym);
  const ps = prices[order.sym];
  const pip = inst ? Math.pow(10, -inst.pipDigits) : 0.0001;
  const rnd = v => inst ? +v.toFixed(inst.digits) : v;
  const [editing, setEditing] = React.useState(false);
  const [trig, setTrig] = React.useState(order.triggerPrice);
  const [tpOn, setTpOn] = React.useState(!!order.tp);
  const [slOn, setSlOn] = React.useState(!!order.sl);
  const isBuySt = order.type.startsWith('Buy');
  const [tp, setTp] = React.useState(order.tp || rnd(order.triggerPrice + (isBuySt ? 50 : -50) * pip));
  const [sl, setSl] = React.useState(order.sl || rnd(order.triggerPrice - (isBuySt ? 50 : -50) * pip));
  const [busy, setBusy] = React.useState(false);
  // { msg, detail } — see PositionActionSheet: FR4 renders the reject CODE and
  // keeps the server's English text as the tooltip.
  const [err, setErr] = React.useState(null);
  if (!inst || !ps) return null;
  const isBuy = isBuySt;
  const isMarket = !order.triggerPrice; // in-flight/held market order: no trigger, not modifiable
  const curPrice = isBuy ? ps.ask : ps.bid;
  const pipsAway = (order.triggerPrice - curPrice) / pip;
  const c = POS_CAT_COLOR[inst.cat] || theme.accent;
  // PL estimate if the entry fills at trig and exits at the given level.
  const estAt = level => computePL({ sym: order.sym, side: order.side, vol: order.vol, openPrice: trig }, level, level);
  const save = async () => {
    if (busy) return;
    setBusy(true); setErr(null);
    const res = await onModify(order, { price: trig, sl: slOn ? sl : 0, tp: tpOn ? tp : 0 });
    setBusy(false);
    if (res.ok) onClose();
    else setErr({
      msg: res.rejectCode ? tCode('reject', res.rejectCode) : (res.error || t('orders.modify.failed')),
      detail: res.error || null,
    });
  };
  const row = (label, val, col) => (
    <div style={{ display: 'flex', justifyContent: 'space-between', padding: '9px 2px', borderBottom: `0.5px solid ${theme.border}` }}>
      <span style={{ fontSize: 13, color: theme.textSec }}>{label}</span>
      <span style={{ fontSize: 13, color: col || theme.text, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>{val}</span>
    </div>
  );
  return (
    <div onClick={onClose} style={{ position: 'absolute', inset: 0, zIndex: 100, background: 'rgba(0,0,0,0.5)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)', display: 'flex', alignItems: 'flex-end', animation: 'fadeIn 180ms ease-out' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', background: theme.bgElevated, borderTopLeftRadius: 24, borderTopRightRadius: 24, padding: '12px 16px 28px', borderTop: `0.5px solid ${theme.border}`, animation: 'slideUp 280ms cubic-bezier(0.2,0.9,0.3,1.05)' }}>
        <div style={{ width: 36, height: 5, borderRadius: 3, background: theme.borderStrong, margin: '0 auto 14px' }} />
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
          <div style={{ width: 34, height: 34, borderRadius: 17, background: `${c}22`, border: `1.5px solid ${c}`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <div style={{ width: 10, height: 10, borderRadius: 5, background: c }} />
          </div>
          <div style={{ flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
              <span style={{ fontSize: 16, fontWeight: 700, color: theme.text, letterSpacing: -0.2 }}>{posPair(order.sym)}</span>
              <span style={{ padding: '2px 7px', borderRadius: 5, fontSize: 10.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.3, color: isBuy ? theme.buy : theme.sell, background: isBuy ? theme.buyBg : theme.sellBg }}>{t('order.type.' + order.typeCode)} {order.vol.toFixed(2)}</span>
              <OriginTag row={order} theme={theme} />
            </div>
            <div style={{ fontSize: 11.5, color: theme.textTer, marginTop: 2, fontVariantNumeric: 'tabular-nums' }}>#{order.ticket} · {order.created}</div>
          </div>
        </div>
        <div style={{ padding: '2px 0 16px' }}>
          {/* Status is a CODE (FR4) — rendered from the code and uppercased by
              CSS, so the bundle keeps natural case. */}
          {!editing && (isMarket
            ? row(t('common.status'), <span style={{ textTransform: 'uppercase' }}>{order.status ? tCode('status', order.status) : ''}</span>)
            : row(t('common.triggerPrice'), fmtPrice(order.triggerPrice, inst.digits)))}
          {row(t('common.currentPrice'), fmtPrice(curPrice, inst.digits))}
          {!editing && !isMarket && row(t('orders.distance'), t('orders.pipsValue', { pips: Math.abs(pipsAway).toFixed(1) }))}
          {!editing && row(t('common.takeProfit'), order.tp ? fmtPrice(order.tp, inst.digits) : '—', order.tp ? theme.buy : theme.textTer)}
          {!editing && row(t('common.stopLoss'), order.sl ? fmtPrice(order.sl, inst.digits) : '—', order.sl ? theme.sell : theme.textTer)}
          {!editing && !isMarket && row(t('common.expiry'), tCode('tif', order.expiry))}
        </div>
        {editing && (
          <div style={{ marginBottom: 10, padding: '9px 12px', borderRadius: 12, background: theme.bgCard, border: `0.5px solid ${theme.border}` }}>
            <div style={{ fontSize: 10, color: theme.textSec, fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.4 }}>{t('common.triggerPrice')}</div>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 6, gap: 4 }}>
              <div onClick={() => setTrig(rnd(trig - pip))} style={{ width: 28, height: 28, borderRadius: 8, background: theme.bgSubtle, display: 'flex', alignItems: 'center', justifyContent: 'center', color: theme.text, fontSize: 17, cursor: 'pointer', flexShrink: 0, userSelect: 'none' }}>−</div>
              <EditablePrice value={trig} setValue={setTrig} inst={inst} size={20} theme={theme} width={120} />
              <div onClick={() => setTrig(rnd(trig + pip))} style={{ width: 28, height: 28, borderRadius: 8, background: theme.bgSubtle, display: 'flex', alignItems: 'center', justifyContent: 'center', color: theme.text, fontSize: 17, cursor: 'pointer', flexShrink: 0, userSelect: 'none' }}>+</div>
            </div>
            <div style={{ fontSize: 10.5, color: theme.textSec, textAlign: 'center', marginTop: 5, fontVariantNumeric: 'tabular-nums' }}>
              {t('orders.pipsFromMarket', { pips: Math.abs((trig - curPrice) / pip).toFixed(1) })}
            </div>
          </div>
        )}
        {editing && (
          <div style={{ display: 'flex', gap: 10, marginBottom: 14 }}>
            <TpSlField kind="tp" on={tpOn} setOn={setTpOn} price={tp} setPrice={setTp}
              onMinus={() => setTp(rnd(tp - pip))} onPlus={() => setTp(rnd(tp + pip))}
              est={estAt(tp)} theme={theme} inst={inst} />
            <TpSlField kind="sl" on={slOn} setOn={setSlOn} price={sl} setPrice={setSl}
              onMinus={() => setSl(rnd(sl - pip))} onPlus={() => setSl(rnd(sl + pip))}
              est={estAt(sl)} theme={theme} inst={inst} />
          </div>
        )}
        {err && <div title={err.detail || undefined} style={{ marginBottom: 10, padding: '8px 12px', borderRadius: 10, background: theme.sellBg, color: theme.sell, fontSize: 12, fontWeight: 600 }}>{err.msg}</div>}
        {!editing ? (
          <div style={{ display: 'flex', gap: 10 }}>
            {!isMarket && <div onClick={() => setEditing(true)} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.bgSubtle, color: theme.text, textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer' }}>{t('common.action.modify')}</div>}
            <div onClick={() => { onConfirmCancel(order); onClose(); }} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.sell, color: '#fff', textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer', boxShadow: `0 6px 16px ${theme.sell}44` }}>
            {t('orders.action.cancelOrder')}
            </div>
          </div>
        ) : (
          <div style={{ display: 'flex', gap: 10 }}>
            <div onClick={() => { setEditing(false); setErr(null); }} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.bgSubtle, color: theme.text, textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer' }}>{t('common.action.back')}</div>
            <div onClick={save} style={{ flex: 1, padding: '14px', borderRadius: 13, background: theme.accent, color: '#fff', textAlign: 'center', fontWeight: 700, fontSize: 14, cursor: 'pointer', opacity: busy ? 0.6 : 1, boxShadow: `0 6px 16px ${theme.accent}44` }}>
              {busy ? t('common.action.saving') : t('common.action.save')}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function OrdersTab({ orders, prices, theme, onTapOrder }) {
  return (
    <div>
      <div style={{ padding: '8px 16px 0' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
          <div style={{ fontSize: 30, fontWeight: 700, color: theme.text, letterSpacing: -0.5 }}>{t('nav.orders')}</div>
          <div style={{ fontSize: 13, color: theme.textSec, whiteSpace: 'nowrap' }}>{t('orders.pendingCount', { n: orders.length })}</div>
        </div>
      </div>

      {orders.length > 0 ? (
        <div style={{ background: theme.bgCard, margin: '14px 16px 0', borderRadius: 14, border: `0.5px solid ${theme.border}`, overflow: 'hidden' }}>
          {orders.map((order, i) => {
            const inst = INSTRUMENTS.find(it => it.sym === order.sym);
            const ps = prices[order.sym];
            if (!inst || !ps) return null;
            return <OrderLine key={order.id} order={order} inst={inst} priceState={ps} theme={theme} onTap={onTapOrder} last={i === orders.length - 1} />;
          })}
        </div>
      ) : (
        <EmptyState
          theme={theme}
          title={t('orders.empty.title')}
          body={t('orders.empty.body')}
        />
      )}

      <div style={{ height: 100 }} />
    </div>
  );
}

function EmptyState({ theme, title, body, icon }) {
  return (
    <div style={{
      padding: '60px 32px', textAlign: 'center',
      display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
    }}>
      <div style={{
        width: 64, height: 64, borderRadius: 16,
        background: theme.bgElevated, border: `0.5px solid ${theme.border}`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        marginBottom: 6,
      }}>
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none">
          <path d="M3 17l6-6 4 4 7-7M21 8v-5h-5" stroke={theme.textSec} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </div>
      <div style={{ fontSize: 17, fontWeight: 600, color: theme.text, letterSpacing: -0.3 }}>{title}</div>
      <div style={{ fontSize: 13.5, color: theme.textSec, maxWidth: 260, lineHeight: 1.4 }}>{body}</div>
    </div>
  );
}

Object.assign(window, { PositionsTab, OrdersTab, NetGroup, TicketLine, PositionActionSheet, OrderLine, OrderActionSheet, EmptyState, OriginTag });
